1 /******************************************************************************
5 * Copyright (C) 1997-2012 by Dimitri van Heesch.
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.
13 * Documents produced by Doxygen are derivative works derived from the
14 * input used in their production; they are not affected by this license.
36 #include <qfileinfo.h>
50 #include "arguments.h"
53 #define YY_NEVER_INTERACTIVE 1
58 FileState(int size) : fileBuf(size),
59 oldFileBuf(0), oldFileBufPos(0) {}
64 YY_BUFFER_STATE bufState;
68 /** @brief Singleton that manages the defines available while
69 * proprocessing files.
73 /** Local class used to hold the defines for a single file */
77 /** Creates an empty container for defines */
78 DefinesPerFile() : m_defines(257), m_includedFiles(17)
80 m_defines.setAutoDelete(TRUE);
82 /** Destroys the object */
83 virtual ~DefinesPerFile()
86 /** Adds a define in the context of a file. Will replace
87 * an existing define with the same name (redefinition)
88 * @param def The Define object to add.
90 void addDefine(Define *def)
92 Define *d = m_defines.find(def->name);
95 m_defines.remove(d->name);
97 m_defines.insert(def->name,def);
99 /** Adds an include file for this file
100 * @param fileName The name of the include file
102 void addInclude(const char *fileName)
104 m_includedFiles.insert(fileName,(void*)0x8);
106 void collectDefines(DefineDict *dict,QDict<void> &includeStack);
108 DefineDict m_defines;
109 QDict<void> m_includedFiles;
113 friend class DefinesPerFile;
114 /** Returns a reference to the singleton */
115 static DefineManager &instance()
117 if (theInstance==0) theInstance = new DefineManager;
120 /** Deletes the singleton */
121 static void deleteInstance()
126 /** Starts a context in which defines are collected.
127 * Called at the start of a new file that is preprocessed.
128 * @param fileName the name of the file to process.
130 void startContext(const char *fileName)
132 //printf("DefineManager::startContext()\n");
133 m_contextDefines.clear();
134 if (fileName==0) return;
135 DefinesPerFile *dpf = m_fileMap.find(fileName);
138 //printf("New file!\n");
139 dpf = new DefinesPerFile;
140 m_fileMap.insert(fileName,dpf);
143 /** Ends the context started with startContext() freeing any
144 * defines collected within in this context.
148 //printf("DefineManager::endContext()\n");
149 m_contextDefines.clear();
151 /** Add an included file to the current context.
152 * If the file has been pre-processed already, all defines are added
154 * @param fileName The name of the include file to add to the context.
156 void addFileToContext(const char *fileName)
158 if (fileName==0) return;
159 //printf("DefineManager::addFileToContext(%s)\n",fileName);
160 DefinesPerFile *dpf = m_fileMap.find(fileName);
163 //printf("New file!\n");
164 dpf = new DefinesPerFile;
165 m_fileMap.insert(fileName,dpf);
169 //printf("existing file!\n");
170 QDict<void> includeStack(17);
171 dpf->collectDefines(&m_contextDefines,includeStack);
175 /** Add a define to the manager object.
176 * @param fileName The file in which the define was found
177 * @param def The Define object to add.
179 void addDefine(const char *fileName,Define *def)
181 if (fileName==0) return;
182 //printf("DefineManager::addDefine(%s,%s)\n",fileName,def->name.data());
183 Define *d = m_contextDefines.find(def->name);
184 if (d!=0) // redefine
186 m_contextDefines.remove(d->name);
188 m_contextDefines.insert(def->name,def);
190 DefinesPerFile *dpf = m_fileMap.find(fileName);
193 dpf = new DefinesPerFile;
198 /** Add an include relation to the manager object.
199 * @param fromFileName file name in which the include was found.
200 * @param toFileName file name that is included.
202 void addInclude(const char *fromFileName,const char *toFileName)
204 //printf("DefineManager::addInclude(%s,%s)\n",fromFileName,toFileName);
205 if (fromFileName==0 || toFileName==0) return;
206 DefinesPerFile *dpf = m_fileMap.find(fromFileName);
209 dpf = new DefinesPerFile;
211 dpf->addInclude(toFileName);
213 /** Returns a Define object given its name or 0 if the Define does
216 Define *isDefined(const char *name) const
218 return m_contextDefines.find(name);
220 /** Returns a reference to the defines found in the current context. */
221 const DefineDict &defineContext() const
223 return m_contextDefines;
226 static DefineManager *theInstance;
228 /** Helper function to collect all define for a given file */
229 void collectDefinesForFile(const char *fileName,DefineDict *dict)
231 if (fileName==0) return;
232 DefinesPerFile *dpf = m_fileMap.find(fileName);
235 QDict<void> includeStack(17);
236 dpf->collectDefines(dict,includeStack);
240 /** Helper function to return the DefinesPerFile object for a given file name. */
241 DefinesPerFile *find(const char *fileName) const
243 if (fileName==0) return 0;
244 return m_fileMap.find(fileName);
247 /** Creates a new DefineManager object */
248 DefineManager() : m_fileMap(1009), m_contextDefines(1009)
250 m_fileMap.setAutoDelete(TRUE);
253 /** Destroys the object */
254 virtual ~DefineManager()
258 QDict<DefinesPerFile> m_fileMap;
259 DefineDict m_contextDefines;
262 /** Singleton instance */
263 DefineManager *DefineManager::theInstance = 0;
265 /** Collects all defines for a file and all files that the file includes.
266 * This function will recursively call itself for each file.
267 * @param dict The dictionary to fill with the defines. A redefine will
268 * replace a previous definition.
269 * @param includeStack The stack of includes, used to stop recursion in
270 * case there is a cyclic include dependency.
272 void DefineManager::DefinesPerFile::collectDefines(
273 DefineDict *dict,QDict<void> &includeStack)
275 //printf("DefinesPerFile::collectDefines #defines=%d\n",m_defines.count());
277 QDictIterator<void> di(m_includedFiles);
278 for (di.toFirst();(di.current());++di)
280 QCString incFile = di.currentKey();
281 DefinesPerFile *dpf = DefineManager::instance().find(incFile);
282 if (dpf && includeStack.find(incFile)==0)
284 //printf(" processing include %s\n",incFile.data());
285 includeStack.insert(incFile,(void*)0x8);
286 dpf->collectDefines(dict,includeStack);
291 QDictIterator<Define> di(m_defines);
293 for (di.toFirst();(def=di.current());++di)
295 Define *d = dict->find(def->name);
296 if (d!=0) // redefine
298 dict->remove(d->name);
300 dict->insert(def->name,def);
301 //printf(" adding define %s\n",def->name.data());
306 /* -----------------------------------------------------------------
311 static int g_yyLineNr = 1;
312 static QCString g_yyFileName;
313 static FileDef *g_yyFileDef;
314 static FileDef *g_inputFileDef;
315 static int g_ifcount = 0;
316 static QStrList *g_pathList = 0;
317 static QStack<FileState> g_includeStack;
318 static QDict<int> *g_argDict;
319 static int g_defArgs = -1;
320 static QCString g_defName;
321 static QCString g_defText;
322 static QCString g_defLitText;
323 static QCString g_defArgsStr;
324 static QCString g_defExtraSpacing;
325 static bool g_defVarArgs;
327 static int g_lastCContext;
328 static int g_lastCPPContext;
329 static QArray<int> g_levelGuard;
330 static BufStr *g_inputBuf;
331 static int g_inputBufPos;
332 static BufStr *g_outputBuf;
333 static int g_roundCount;
334 static bool g_quoteArg;
335 static DefineDict *g_expandedDict;
336 static int g_findDefArgContext;
337 static bool g_expectGuard;
338 static QCString g_guardName;
339 static QCString g_lastGuardName;
340 static QCString g_incName;
341 static QCString g_guardExpr;
342 static int g_curlyCount;
343 static bool g_nospaces; // add extra spaces during macro expansion
345 static bool g_macroExpansion; // from the configuration
346 static bool g_expandOnlyPredef; // from the configuration
347 static int g_commentCount;
348 static bool g_insideComment;
349 static bool g_isImported;
350 static QCString g_blockName;
351 static int g_condCtx;
353 static QStack<bool> g_condStack;
354 static bool g_insideCS; // C# has simpler preprocessor
355 static bool g_isSource;
357 static bool g_lexInit = FALSE;
359 //DefineDict* getGlobalDefineDict()
361 // return g_globalDefineDict;
364 static void setFileName(const char *name)
368 g_yyFileName=convertToQCString(fi.absFilePath());
369 g_yyFileDef=findFileDef(Doxygen::inputNameDict,g_yyFileName,ambig);
370 if (g_yyFileDef==0) // if this is not an input file check if it is an
373 g_yyFileDef=findFileDef(Doxygen::includeNameDict,g_yyFileName,ambig);
375 //printf("setFileName(%s) g_yyFileName=%s g_yyFileDef=%p\n",
376 // name,g_yyFileName.data(),g_yyFileDef);
377 if (g_yyFileDef && g_yyFileDef->isReference()) g_yyFileDef=0;
378 g_insideCS = getLanguageFromFileName(g_yyFileName)==SrcLangExt_CSharp;
379 g_isSource = guessSection(g_yyFileName);
382 static void incrLevel()
385 g_levelGuard.resize(g_level);
386 g_levelGuard[g_level-1]=FALSE;
387 //printf("%s line %d: incrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level);
390 static void decrLevel()
392 //printf("%s line %d: decrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level);
396 g_levelGuard.resize(g_level);
400 warn(g_yyFileName,g_yyLineNr,"warning: More #endif's than #if's found.\n");
404 static bool otherCaseDone()
408 warn(g_yyFileName,g_yyLineNr,"warning: Found an #else without a preceding #if.\n");
413 return g_levelGuard[g_level-1];
417 static void setCaseDone(bool value)
419 g_levelGuard[g_level-1]=value;
423 static bool macroIsAccessible(Define *def)
425 //printf("macroIsAccessible(%s) input=%s def=%s\n",
426 // def->name.data(),g_inputFileDef?g_inputFileDef->name().data():"<none>",
427 // def->fileDef ? def->fileDef->name().data() : "<none>");
428 if (def && def->isPredefined) // predefined macro -> globally accessible
430 //printf("%s: predefined macro %s\n",g_inputFileDef->name().data(),def->name.data());
433 if (def && def->fileDef==g_inputFileDef)
435 //printf("%s: macro %s defined in this file at line %d now at %d\n",
436 // g_inputFileDef->name().data(),def->name.data(),def->lineNr,g_yyLineNr);
437 return def->lineNr<=g_yyLineNr;
439 if (g_inputFileDef && def && def->fileDef) // check if g_inputFileDef actually includes def->fileDef
441 QDict<FileDef> includedFiles(257);
442 bool b = g_inputFileDef->includes(def->fileDef,&includedFiles);
443 //printf("%s: Checking for accessibility of define '%s' (defined in %s): result=%d\n",
444 // g_inputFileDef->name().data(),def->name.data(),def->fileDef->name().data(),b);
447 if (g_inputFileDef && def && !def->fileName.isEmpty())
449 bool b = g_inputFileDef->includesByName(def->fileName);
450 //printf("%s: Checking for accessibility of define '%s' (defined in %s): result=%d\n",
451 // g_inputFileDef->name().data(),def->name.data(),def->fileName.data(),b);
454 //printf("not accessible!\n");
458 static Define *isDefined(const char *name)
463 def=g_globalDefineDict->find(name);
464 if (def && def->undef) def=0;
465 if (def && !macroIsAccessible(def)) def=0;
467 //printf("isDefined(%s)=%p\n",name,def);
473 static QDict<void> g_allIncludes(10009);
475 static FileState *checkAndOpenFile(const QCString &fileName,bool &alreadyIncluded)
477 alreadyIncluded = FALSE;
479 //printf("checkAndOpenFile(%s)\n",fileName.data());
480 QFileInfo fi(fileName);
481 if (fi.exists() && fi.isFile())
483 static QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
484 if (patternMatch(fi,&exclPatterns)) return 0;
486 QCString absName = convertToQCString(fi.absFilePath());
489 if (g_curlyCount==0) // not #include inside { ... }
491 if (g_allIncludes.find(absName)!=0)
493 alreadyIncluded = TRUE;
494 //printf(" already included 1\n");
495 return 0; // already done
497 g_allIncludes.insert(absName,(void *)0x8);
499 // check include stack for absName
501 QStack<FileState> tmpStack;
502 g_includeStack.setAutoDelete(FALSE);
503 while ((fs=g_includeStack.pop()))
505 if (fs->fileName==absName) alreadyIncluded=TRUE;
508 while ((fs=tmpStack.pop()))
510 g_includeStack.push(fs);
512 g_includeStack.setAutoDelete(TRUE);
516 //printf(" already included 2\n");
519 //printf("#include %s\n",absName.data());
521 fs = new FileState(fi.size()+4096);
522 alreadyIncluded = FALSE;
523 if (!readInputFile(absName,fs->fileBuf))
525 //printf(" error reading\n");
531 fs->oldFileBuf = g_inputBuf;
532 fs->oldFileBufPos = g_inputBufPos;
538 static FileState *findFile(const char *fileName,bool localInclude,bool &alreadyIncluded)
540 //printf("** findFile(%s,%d) g_yyFileName=%s\n",fileName,localInclude,g_yyFileName.data());
541 if (localInclude && !g_yyFileName.isEmpty())
543 QFileInfo fi(g_yyFileName);
546 QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+fileName;
547 FileState *fs = checkAndOpenFile(absName,alreadyIncluded);
550 setFileName(absName);
554 else if (alreadyIncluded)
564 char *s=g_pathList->first();
567 QCString absName = (QCString)s+"/"+fileName;
568 //printf(" Looking for %s in %s\n",fileName,s);
569 FileState *fs = checkAndOpenFile(absName,alreadyIncluded);
572 setFileName(absName);
574 //printf(" -> found it\n");
577 else if (alreadyIncluded)
582 s=g_pathList->next();
587 static QCString extractTrailingComment(const char *s)
599 if (i>=0 && s[i]=='*') // end of a comment block
602 while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--;
607 // only /*!< or /**< are treated as a comment for the macro name,
608 // otherwise the comment is treated as part of the macro definition
609 return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : "";
617 // whitespace or line-continuation
632 static int getNextChar(const QCString &expr,QCString *rest,uint &pos);
633 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos);
634 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c);
635 static void expandExpression(QCString &expr,QCString *rest,int pos);
637 static QCString stringize(const QCString &s)
646 if (!inString && !inChar)
648 while (i<s.length() && !inString && !inChar)
669 while (i<s.length() && inChar)
690 while (i<s.length() && inString)
706 //printf("stringize `%s'->`%s'\n",s.data(),result.data());
710 /*! Execute all ## operators in expr.
711 * If the macro name before or after the operator contains a no-rescan
712 * marker (@-) then this is removed (before the concatenated macro name
713 * may be expanded again.
715 static void processConcatOperators(QCString &expr)
717 //printf("processConcatOperators: in=`%s'\n",expr.data());
718 QRegExp r("[ \\t\\n]*##[ \\t\\n]*");
720 if (expr.isEmpty()) return;
721 while ((n=r.match(expr,i,&l))!=-1)
723 //printf("Match: `%s'\n",expr.data()+i);
724 if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-')
726 // remove no-rescan marker after ID
729 //printf("found `%s'\n",expr.mid(n,l).data());
730 // remove the ## operator and the surrounding whitespace
731 expr=expr.left(n)+expr.right(expr.length()-n-l);
733 while (k>=0 && isId(expr.at(k))) k--;
734 if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@')
736 // remove no-rescan marker before ID
737 expr=expr.left(k-1)+expr.right(expr.length()-k-1);
742 //printf("processConcatOperators: out=`%s'\n",expr.data());
745 static void yyunput (int c,char *buf_ptr );
746 static void returnCharToStream(char c)
751 static inline void addTillEndOfString(const QCString &expr,QCString *rest,
752 uint &pos,char term,QCString &arg)
755 while ((cc=getNextChar(expr,rest,pos))!=EOF)
757 if (cc=='\\') arg+=(char)cc,cc=getNextChar(expr,rest,pos);
758 else if (cc==term) return;
763 /*! replaces the function macro \a def whose argument list starts at
764 * \a pos in expression \a expr.
765 * Notice that this routine may scan beyond the \a expr string if needed.
766 * In that case the characters will be read from the input file.
767 * The replacement string will be returned in \a result and the
768 * length of the (unexpanded) argument list is stored in \a len.
770 static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result)
772 //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);
777 while ((cc=getCurrentChar(expr,rest,j))!=EOF && isspace(cc))
780 getNextChar(expr,rest,j);
784 unputChar(expr,rest,j,' ');
787 getNextChar(expr,rest,j); // eat the `(' character
789 QDict<QCString> argTable; // list of arguments
790 argTable.setAutoDelete(TRUE);
795 // PHASE 1: read the macro arguments
798 while ((cc=getNextChar(expr,rest,j))!=EOF)
806 while (!done && (argCount<def->nargs || def->varArgs) &&
807 ((cc=getNextChar(expr,rest,j))!=EOF)
811 if (c=='(') // argument is a function => search for matching )
816 while ((cc=getNextChar(expr,rest,j))!=EOF)
819 //printf("processing %c: term=%c (%d)\n",c,term,term);
820 if (c=='\'' || c=='\"') // skip ('s and )'s inside strings
823 addTillEndOfString(expr,rest,j,c,arg);
840 else if (c==')' || c==',') // last or next argument found
842 if (c==',' && argCount==def->nargs-1 && def->varArgs)
844 arg=arg.stripWhiteSpace();
850 argKey.sprintf("@%d",argCount++); // key name
851 arg=arg.stripWhiteSpace();
852 // add argument to the lookup table
853 argTable.insert(argKey, new QCString(arg));
855 if (c==')') // end of the argument list
861 else if (c=='\"') // append literal strings
865 while (!found && (cc=getNextChar(expr,rest,j))!=EOF)
872 if ((cc=getNextChar(expr,rest,j))==EOF) break;
878 else if (c=='\'') // append literal characters
882 while (!found && (cc=getNextChar(expr,rest,j))!=EOF)
889 if ((cc=getNextChar(expr,rest,j))==EOF) break;
895 else // append other characters
902 // PHASE 2: apply the macro function
903 if (argCount==def->nargs ||
904 (argCount>def->nargs && def->varArgs)) // matching parameters lists
907 // substitution of all formal arguments
909 const QCString d=def->definition.stripWhiteSpace();
910 //printf("Macro definition: %s\n",d.data());
914 if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
916 if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
919 resExpr+="@@"; // we unescape these later
921 else if (d.at(k+1)=='-') // no-rescan marker
926 else // argument marker => read the argument number
932 // search for ## backward
933 if (l>=0 && d.at(l)=='"') l--;
934 while (l>=0 && d.at(l)==' ') l--;
935 if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
938 while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
941 // search for ## forward
943 if (l<(int)d.length() && d.at(l)=='"') l++;
944 while (l<(int)d.length() && d.at(l)==' ') l++;
945 if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
947 //printf("request key %s result %s\n",key.data(),argTable[key]->data());
948 if (key.length()>1 && (subst=argTable[key]))
950 QCString substArg=*subst;
951 //printf("substArg=`%s'\n",substArg.data());
952 // only if no ## operator is before or after the argument
953 // marker we do macro expansion.
954 if (!hash) expandExpression(substArg,0,0);
957 //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data());
959 // if the marker is inside a string (because a # was put
960 // before the macro name) we must escape " and \ characters
961 resExpr+=stringize(substArg);
965 if (hash && substArg.isEmpty())
967 resExpr+="@E"; // empty argument will be remove later on
975 resExpr+=" "+substArg+" ";
981 else // no marker, just copy
983 if (!inString && d.at(k)=='\"')
985 inString=TRUE; // entering a literal string
987 else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
989 inString=FALSE; // leaving a literal string
996 //printf("result after substitution `%s' expr=`%s'\n",
997 // result.data(),expr.mid(pos,len).data());
1004 /*! returns the next identifier in string \a expr by starting at position \a p.
1005 * The position of the identifier is returned (or -1 if nothing is found)
1006 * and \a l is its length. Any quoted strings are skipping during the search.
1008 static int getNextId(const QCString &expr,int p,int *l)
1011 while (p<(int)expr.length())
1013 char c=expr.at(p++);
1014 if (isdigit(c)) // skip number
1016 while (p<(int)expr.length() && isId(expr.at(p))) p++;
1018 else if (isalpha(c) || c=='_') // read id
1021 while (p<(int)expr.length() && isId(expr.at(p))) p++;
1025 else if (c=='"') // skip string
1028 if (p<(int)expr.length()) c=expr.at(p);
1029 while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\')))
1030 // continue as long as no " is found, but ignoring \", but not \\"
1037 if (p<(int)expr.length()) ++p; // skip closing quote
1039 else if (c=='/') // skip C Comment
1041 //printf("Found C comment at p=%d\n",p);
1043 if (p<(int)expr.length())
1046 if (c=='*') // Start of C comment
1049 while (p<(int)expr.length() && !(pc=='*' && c=='/'))
1056 //printf("Found end of C comment at p=%d\n",p);
1062 /*! preforms recursive macro expansion on the string \a expr
1063 * starting at position \a pos.
1064 * May read additional characters from the input while re-scanning!
1065 * If \a expandAll is \c TRUE then all macros in the expression are
1066 * expanded, otherwise only the first is expanded.
1068 static void expandExpression(QCString &expr,QCString *rest,int pos)
1070 //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0);
1073 bool definedTest=FALSE;
1075 while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
1077 bool replaced=FALSE;
1078 macroName=expr.mid(p,l);
1079 //printf("macroName=%s\n",macroName.data());
1080 if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
1082 if (g_expandedDict->find(macroName)==0) // expand macro
1084 Define *def=DefineManager::instance().isDefined(macroName);
1085 if (definedTest) // macro name was found after defined
1087 if (def) expMacro = " 1 "; else expMacro = " 0 ";
1092 else if (def && def->nargs==-1) // simple macro
1094 // substitute the definition of the macro
1095 //printf("macro `%s'->`%s'\n",macroName.data(),def->definition.data());
1098 expMacro=def->definition.stripWhiteSpace();
1102 expMacro=" "+def->definition.stripWhiteSpace()+" ";
1104 //expMacro=def->definition.stripWhiteSpace();
1107 //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data());
1109 else if (def && def->nargs>=0) // function macro
1111 replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro);
1114 else if (macroName=="defined")
1116 //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data());
1120 if (replaced) // expand the macro and rescan the expression
1123 //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data());
1124 QCString resultExpr=expMacro;
1125 QCString restExpr=expr.right(expr.length()-len-p);
1126 processConcatOperators(resultExpr);
1127 if (def && !def->nonRecursive)
1129 g_expandedDict->insert(macroName,def);
1130 expandExpression(resultExpr,&restExpr,0);
1131 g_expandedDict->remove(macroName);
1133 expr=expr.left(p)+resultExpr+restExpr;
1135 //printf("new expression: %s\n",expr.data());
1137 else // move to the next macro name
1139 //printf("moving to the next macro old=%d new=%d\n",i,p+l);
1143 else // move to the next macro name
1145 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
1146 //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data());
1151 else // no re-scan marker found, skip the macro name
1153 //printf("skipping marked macro\n");
1159 /*! replaces all occurrences of @@@@ in \a s by @@
1160 * and removes all occurrences of @@E.
1161 * All identifiers found are replaced by 0L
1163 QCString removeIdsAndMarkers(const char *s)
1165 //printf("removeIdsAndMarkers(%s)\n",s);
1174 if (c=='@') // replace @@ with @ and remove @E
1180 else if (*(p+1)=='E')
1186 else if (isdigit(c)) // number
1192 else if (c=='d' && !inNum) // identifier starting with a `d'
1194 if (strncmp(p,"defined ",8)==0 || strncmp(p,"defined(",8)==0)
1197 p+=7; // skip defined
1203 while ((c=*p) && isId(c)) p++;
1206 else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
1210 while ((c=*p) && isId(c)) p++;
1211 if (*p=='(') // undefined function macro
1217 if (c=='(') count++;
1221 if (count==0) break;
1227 if (c=='*') // start of C comment
1229 while (*p && !(pc=='*' && c=='/')) // search end of comment
1240 else if (c=='/') // skip C comments
1244 if (c=='*') // start of C comment
1246 while (*p && !(pc=='*' && c=='/')) // search end of comment
1253 else // oops, not comment but division
1264 if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE;
1269 //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data());
1273 /*! replaces all occurrences of @@ in \a s by @
1275 * \a s only contains pairs of @@'s
1277 QCString removeMarkers(const char *s)
1288 case '@': // replace @@ with @
1297 case '/': // skip C comments
1302 if (c=='*') // start of C comment
1304 while (*p && !(pc=='*' && c=='/')) // search end of comment
1306 if (*p=='@' && *(p+1)=='@')
1313 if (*p) result+=c,p++;
1317 case '"': // skip string literals
1322 while (*p && (c!='"' || pc=='\\')) // no end quote
1327 if (*p) result+=c,p++;
1330 case '\'': // skip char literals
1335 while (*p && (c!='\'' || pc=='\\')) // no end quote
1340 if (*p) result+=c,p++;
1352 //printf("RemoveMarkers(%s)=%s\n",s,result.data());
1356 /*! compute the value of the expression in string \a expr.
1357 * If needed the function may read additional characters from the input.
1360 bool computeExpression(const QCString &expr)
1363 expandExpression(e,0,0);
1364 //printf("after expansion `%s'\n",e.data());
1365 e = removeIdsAndMarkers(e);
1366 if (e.isEmpty()) return FALSE;
1367 //printf("parsing `%s'\n",e.data());
1368 return parseCppExpression(g_yyFileName,g_yyLineNr,e);
1371 /*! expands the macro definition in \a name
1372 * If needed the function may read additional characters from the input
1375 QCString expandMacro(const QCString &name)
1378 expandExpression(n,0,0);
1380 //printf("expandMacro `%s'->`%s'\n",name.data(),n.data());
1386 Define *def=new Define;
1387 def->name = g_defName;
1388 def->definition = g_defText.stripWhiteSpace();
1389 def->nargs = g_defArgs;
1390 def->fileName = g_yyFileName;
1391 def->fileDef = g_yyFileDef;
1392 def->lineNr = g_yyLineNr;
1393 def->varArgs = g_defVarArgs;
1394 //printf("newDefine: %s %s file: %s\n",def->name.data(),def->definition.data(),
1395 // def->fileDef ? def->fileDef->name().data() : def->fileName.data());
1396 //printf("newDefine: `%s'->`%s'\n",def->name.data(),def->definition.data());
1397 if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name])
1399 def->isPredefined=TRUE;
1406 if (g_skip) return; // do not add this define as it is inside a
1407 // conditional section (cond command) that is disabled.
1408 if (!Doxygen::gatherDefines) return;
1410 //printf("addDefine %s %s\n",g_defName.data(),g_defArgsStr.data());
1411 //ArgumentList *al = new ArgumentList;
1412 //stringToArgumentList(g_defArgsStr,al);
1413 MemberDef *md=new MemberDef(
1414 g_yyFileName,g_yyLineNr,
1415 "#define",g_defName,g_defArgsStr,0,
1416 Public,Normal,FALSE,Member,MemberDef::Define,0,0);
1417 if (!g_defArgsStr.isEmpty())
1419 ArgumentList *argList = new ArgumentList;
1420 //printf("addDefine() g_defName=`%s' g_defArgsStr=`%s'\n",g_defName.data(),g_defArgsStr.data());
1421 stringToArgumentList(g_defArgsStr,argList);
1422 md->setArgumentList(argList);
1424 //printf("Setting initializer for `%s' to `%s'\n",g_defName.data(),g_defText.data());
1425 int l=g_defLitText.find('\n');
1426 if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\")
1428 // strip first line if it only contains a slash
1429 g_defLitText = g_defLitText.right(g_defLitText.length()-l-1);
1433 // align the items on the first line with the items on the second line
1435 const char *p=g_defLitText.data()+k;
1437 while ((c=*p++) && (c==' ' || c=='\t')) k++;
1438 g_defLitText=g_defLitText.mid(l+1,k-l-1)+g_defLitText.stripWhiteSpace();
1440 md->setInitializer(g_defLitText.stripWhiteSpace());
1442 //printf("pre.l: md->setFileDef(%p)\n",g_inputFileDef);
1443 md->setFileDef(g_inputFileDef);
1444 md->setDefinition("#define "+g_defName);
1446 MemberName *mn=Doxygen::functionNameSDict->find(g_defName);
1449 mn = new MemberName(g_defName);
1450 Doxygen::functionNameSDict->append(g_defName,mn);
1455 g_yyFileDef->insertMember(md);
1459 //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine());
1462 static inline void outputChar(char c)
1464 if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addChar(c);
1467 static inline void outputArray(const char *a,int len)
1469 if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addArray(a,len);
1472 static void readIncludeFile(const QCString &inc)
1474 static bool searchIncludes = Config_getBool("SEARCH_INCLUDES");
1475 if (!searchIncludes) return; // do not read include files
1478 // find the start of the include file name
1479 while (i<inc.length() &&
1480 (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
1484 // was it a local include?
1485 bool localInclude = s>0 && inc.at(s-1)=='"';
1487 // find the end of the include file name
1488 while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
1490 if (s<inc.length() && i>s) // valid include file name found
1492 // extract include path+name
1493 QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
1495 QCString dosExt = incFileName.right(4);
1496 if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb")
1498 // skip imported binary files (e.g. M$ type libraries)
1502 QCString oldFileName = g_yyFileName;
1503 FileDef *oldFileDef = g_yyFileDef;
1504 int oldLineNr = g_yyLineNr;
1505 //printf("Searching for `%s'\n",incFileName.data());
1507 // absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336)
1508 QCString absIncFileName = incFileName;
1510 static bool searchIncludes = Config_getBool("SEARCH_INCLUDES");
1511 QFileInfo fi(g_yyFileName);
1514 QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName;
1515 QFileInfo fi2(absName);
1518 absIncFileName=fi2.absFilePath().utf8();
1520 else if (searchIncludes) // search in INCLUDE_PATH as well
1522 QStrList &includePath = Config_getList("INCLUDE_PATH");
1523 char *s=includePath.first();
1527 if (fi.exists() && fi.isDir())
1529 QCString absName = QCString(fi.absFilePath().utf8())+"/"+incFileName;
1530 //printf("trying absName=%s\n",absName.data());
1531 QFileInfo fi2(absName);
1534 absIncFileName=fi2.absFilePath().utf8();
1537 //printf( "absIncFileName = %s\n", absIncFileName.data() );
1539 s=includePath.next();
1542 //printf( "absIncFileName = %s\n", absIncFileName.data() );
1545 DefineManager::instance().addInclude(g_yyFileName,absIncFileName);
1546 DefineManager::instance().addFileToContext(absIncFileName);
1548 // findFile will overwrite g_yyFileDef if found
1550 bool alreadyIncluded = FALSE;
1551 //printf("calling findFile(%s)\n",incFileName.data());
1552 if ((fs=findFile(incFileName,localInclude,alreadyIncluded))) // see if the include file can be found
1554 //printf("Found include file!\n");
1555 if (Debug::isFlagSet(Debug::Preprocessor))
1557 for (i=0;i<g_includeStack.count();i++)
1559 Debug::print(Debug::Preprocessor,0," ");
1561 //msg("#include %s: parsing...\n",incFileName.data());
1565 // add include dependency to the file in which the #include was found
1567 // change to absolute name for bug 641336
1568 FileDef *incFd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1569 oldFileDef->addIncludeDependency(ambig ? 0 : incFd,incFileName,localInclude,g_isImported,FALSE);
1570 // add included by dependency
1573 //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data());
1574 g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1577 else if (g_inputFileDef)
1579 g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1581 fs->bufState = YY_CURRENT_BUFFER;
1582 fs->lineNr = oldLineNr;
1583 fs->fileName = oldFileName;
1584 // push the state on the stack
1585 g_includeStack.push(fs);
1586 // set the scanner to the include file
1588 // Deal with file changes due to
1589 // #include's within { .. } blocks
1590 QCString lineStr(g_yyFileName.length()+20);
1591 lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data());
1592 outputArray(lineStr.data(),lineStr.length());
1594 //fprintf(stderr,"Switching to include file %s\n",incFileName.data());
1596 g_inputBuf = &fs->fileBuf;
1598 yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE));
1602 //printf(" calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded);
1606 //QCString absPath = incFileName;
1607 //if (QDir::isRelativePath(incFileName))
1609 // absPath = QDir::cleanDirPath(oldFileDef->getPath()+"/"+incFileName);
1610 // //printf("%s + %s -> resolved path %s\n",oldFileDef->getPath().data(),incFileName.data(),absPath.data());
1613 // change to absolute name for bug 641336
1614 FileDef *fd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1615 //printf("%s::findFileDef(%s)=%p\n",oldFileDef->name().data(),incFileName.data(),fd);
1616 // add include dependency to the file in which the #include was found
1617 oldFileDef->addIncludeDependency(ambig ? 0 : fd,incFileName,localInclude,g_isImported,FALSE);
1618 // add included by dependency
1621 //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig);
1622 fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1625 else if (g_inputFileDef)
1627 g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1629 if (Debug::isFlagSet(Debug::Preprocessor))
1631 if (alreadyIncluded)
1633 Debug::print(Debug::Preprocessor,0,"#include %s: already included! skipping...\n",incFileName.data());
1637 Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",incFileName.data());
1639 //printf("error: include file %s not found\n",yytext);
1641 if (g_curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... }
1643 warn(g_yyFileName,g_yyLineNr,"Warning: include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data());
1649 /* ----------------------------------------------------------------- */
1651 static void startCondSection(const char *sectId)
1653 g_condStack.push(new bool(g_skip));
1654 if (Config_getList("ENABLED_SECTIONS").find(sectId)==-1)
1660 static void endCondSection()
1662 if (g_condStack.isEmpty())
1668 bool *ctx = g_condStack.pop();
1673 static void forceEndCondSection()
1675 while (!g_condStack.isEmpty())
1682 static QCString escapeAt(const char *text)
1691 if (c=='@') result+="@@"; else result+=c;
1697 static char resolveTrigraph(char c)
1701 case '=': return '#';
1702 case '/': return '\\';
1703 case '\'': return '^';
1704 case '(': return '[';
1705 case ')': return ']';
1706 case '!': return '|';
1707 case '<': return '{';
1708 case '>': return '}';
1709 case '-': return '~';
1714 /* ----------------------------------------------------------------- */
1717 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
1719 static int yyread(char *buf,int max_size)
1721 int bytesInBuf = g_inputBuf->curPos()-g_inputBufPos;
1722 int bytesToCopy = QMIN(max_size,bytesInBuf);
1723 memcpy(buf,g_inputBuf->data()+g_inputBufPos,bytesToCopy);
1724 g_inputBufPos+=bytesToCopy;
1728 /* ----------------------------------------------------------------- */
1732 ID [a-z_A-Z][a-z_A-Z0-9]*
1735 CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
1777 <*>"??"[=/'()!<>-] { // Trigraph
1778 unput(resolveTrigraph(yytext[2]));
1780 <Start>^{B}*"#" { BEGIN(Command); }
1782 outputArray(yytext,yyleng);
1785 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors?
1787 for (i=yyleng-1;i>=0;i--)
1793 <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
1794 <Start>^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\)\n]*")"{B}*\n { // function like macro
1795 static bool skipFuncMacros = Config_getBool("SKIP_FUNCTION_MACROS");
1796 QCString name(yytext);
1797 name=name.left(name.find('(')).stripWhiteSpace();
1800 if (skipFuncMacros &&
1801 name!="Q_PROPERTY" &&
1803 (g_includeStack.isEmpty() || g_curlyCount>0) &&
1805 (def=DefineManager::instance().isDefined(name)) &&
1806 /*macroIsAccessible(def) &&*/
1807 (!g_expandOnlyPredef || def->isPredefined)
1817 for (i=yyleng-1;i>=0;i--)
1824 <CopyLine>"extern"{BN}{0,80}"\"C\""*{BN}{0,80}"{" {
1825 QCString text=yytext;
1826 g_yyLineNr+=text.contains('\n');
1827 outputArray(yytext,yyleng);
1829 <CopyLine>"{" { // count brackets inside the main file
1830 if (g_includeStack.isEmpty())
1834 outputChar(*yytext);
1836 <CopyLine>"}" { // count brackets inside the main file
1837 if (g_includeStack.isEmpty() && g_curlyCount>0)
1841 outputChar(*yytext);
1843 <CopyLine>"'"\\[0-7]{1,3}"'" {
1844 outputArray(yytext,yyleng);
1846 <CopyLine>"'"\\."'" {
1847 outputArray(yytext,yyleng);
1850 outputArray(yytext,yyleng);
1853 outputChar(*yytext);
1854 BEGIN( CopyString );
1856 <CopyString>[^\"\\\r\n]+ {
1857 outputArray(yytext,yyleng);
1860 outputArray(yytext,yyleng);
1863 outputChar(*yytext);
1866 <CopyLine>{ID}/{BN}{0,80}"(" {
1867 g_expectGuard = FALSE;
1869 //def=g_globalDefineDict->find(yytext);
1870 //def=DefineManager::instance().isDefined(yytext);
1871 //printf("Search for define %s found=%d g_includeStack.isEmpty()=%d "
1872 // "g_curlyCount=%d g_macroExpansion=%d g_expandOnlyPredef=%d "
1873 // "isPreDefined=%d\n",yytext,def ? 1 : 0,
1874 // g_includeStack.isEmpty(),g_curlyCount,g_macroExpansion,g_expandOnlyPredef,
1875 // def ? def->isPredefined : -1
1877 if ((g_includeStack.isEmpty() || g_curlyCount>0) &&
1879 (def=DefineManager::instance().isDefined(yytext)) &&
1880 /*(def->isPredefined || macroIsAccessible(def)) && */
1881 (!g_expandOnlyPredef || def->isPredefined)
1884 //printf("Found it! #args=%d\n",def->nargs);
1886 g_defArgsStr=yytext;
1887 if (def->nargs==-1) // no function macro
1889 QCString result = def->isPredefined ? def->definition : expandMacro(g_defArgsStr);
1890 outputArray(result,result.length());
1892 else // zero or more arguments
1894 g_findDefArgContext = CopyLine;
1895 BEGIN(FindDefineArgs);
1900 outputArray(yytext,yyleng);
1905 if ((g_includeStack.isEmpty() || g_curlyCount>0) &&
1907 (def=DefineManager::instance().isDefined(yytext)) &&
1909 /*(def->isPredefined || macroIsAccessible(def)) &&*/
1910 (!g_expandOnlyPredef || def->isPredefined)
1913 QCString result=def->isPredefined ? def->definition : expandMacro(yytext);
1914 outputArray(result,result.length());
1918 outputArray(yytext,yyleng);
1921 <CopyLine>"\\"\r?/\n { // strip line continuation characters
1924 outputChar(*yytext);
1931 <FindDefineArgs>"(" {
1935 <FindDefineArgs>")" {
1938 if (g_roundCount==0)
1940 QCString result=expandMacro(g_defArgsStr);
1941 //printf("g_defArgsStr=`%s'->`%s'\n",g_defArgsStr.data(),result.data());
1942 if (g_findDefArgContext==CopyLine)
1944 outputArray(result,result.length());
1945 BEGIN(g_findDefArgContext);
1947 else // g_findDefArgContext==IncludeID
1949 readIncludeFile(result);
1956 <FindDefineArgs>")"{B}*"(" {
1957 g_defArgsStr+=yytext;
1960 <FindDefineArgs>{CHARLIT} {
1961 g_defArgsStr+=yytext;
1963 <FindDefineArgs>\" {
1964 g_defArgsStr+=*yytext;
1967 <FindDefineArgs>\n {
1971 <FindDefineArgs>"@" {
1975 g_defArgsStr+=*yytext;
1978 g_defArgsStr+=*yytext;
1979 BEGIN(FindDefineArgs);
1981 <ReadString>"//"|"/*" {
1982 g_defArgsStr+=yytext;
1985 g_defArgsStr+=yytext;
1988 g_defArgsStr+=*yytext;
1990 <Command>("include"|"import"){B}+/{ID} {
1991 g_isImported = yytext[1]=='m';
1992 if (g_macroExpansion)
1995 <Command>("include"|"import"){B}*[<"] {
1996 g_isImported = yytext[1]=='m';
1998 c[0]=yytext[yyleng-1];c[1]='\0';
2002 <Command>("cmake")?"define"{B}+ {
2003 //printf("!!!DefName\n");
2006 <Command>"ifdef"/{B}*"(" {
2008 g_guardExpr.resize(0);
2009 BEGIN(DefinedExpr2);
2011 <Command>"ifdef"/{B}+ {
2012 //printf("Pre.l: ifdef\n");
2014 g_guardExpr.resize(0);
2015 BEGIN(DefinedExpr1);
2017 <Command>"ifndef"/{B}*"(" {
2020 BEGIN(DefinedExpr2);
2022 <Command>"ifndef"/{B}+ {
2025 BEGIN(DefinedExpr1);
2027 <Command>"if"/[ \t(!] {
2029 g_guardExpr.resize(0);
2032 <Command>("elif"|"else"{B}*"if")/[ \t(!] {
2033 if (!otherCaseDone())
2035 g_guardExpr.resize(0);
2041 BEGIN(SkipCPPBlock);
2044 <Command>"else"/[^a-z_A-Z0-9] {
2045 //printf("else g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2046 if (otherCaseDone())
2049 BEGIN(SkipCPPBlock);
2054 //g_levelGuard[g_level-1]=TRUE;
2057 <Command>"undef"{B}+ {
2060 <Command>("elif"|"else"{B}*"if")/[ \t(!] {
2061 if (!otherCaseDone())
2063 g_guardExpr.resize(0);
2067 <Command>"endif"/[^a-z_A-Z0-9] {
2068 //printf("Pre.l: #endif\n");
2071 <Command,IgnoreLine>\n {
2076 <Command>"pragma"{B}+"once" {
2077 g_expectGuard = FALSE;
2079 <Command>{ID} { // unknown directive
2082 <IgnoreLine>\\[\r]?\n {
2090 if ((def=DefineManager::instance().isDefined(yytext))
2091 /*&& !def->isPredefined*/
2092 && !def->nonRecursive
2095 //printf("undefining %s\n",yytext);
2105 <Guard>"defined"/{B}*"(" {
2106 BEGIN(DefinedExpr2);
2108 <Guard>"defined"/{B}+ {
2109 BEGIN(DefinedExpr1);
2111 <Guard>{ID} { g_guardExpr+=yytext; }
2112 <Guard>. { g_guardExpr+=*yytext; }
2115 //printf("Guard: `%s'\n",
2116 // g_guardExpr.data());
2117 bool guard=computeExpression(g_guardExpr);
2119 //printf("if g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2127 BEGIN(SkipCPPBlock);
2130 <DefinedExpr1,DefinedExpr2>\\\n { g_yyLineNr++; outputChar('\n'); }
2131 <DefinedExpr1>{ID} {
2132 if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2133 g_guardExpr+=" 1L ";
2135 g_guardExpr+=" 0L ";
2136 g_lastGuardName=yytext;
2139 <DefinedExpr2>{ID} {
2140 if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2141 g_guardExpr+=" 1L ";
2143 g_guardExpr+=" 0L ";
2144 g_lastGuardName=yytext;
2146 <DefinedExpr1,DefinedExpr2>\n { // should not happen, handle anyway
2149 BEGIN(SkipCPPBlock);
2154 <DefinedExpr1,DefinedExpr2>.
2155 <SkipCPPBlock>^{B}*"#" { BEGIN(SkipCommand); }
2156 <SkipCPPBlock>^{B}*/[^#] { BEGIN(SkipLine); }
2157 <SkipCPPBlock>\n { g_yyLineNr++; outputChar('\n'); }
2159 <SkipCommand>"if"(("n")?("def"))?/[ \t(!] {
2162 //printf("#if... depth=%d\n",g_ifcount);
2164 <SkipCommand>"else" {
2165 //printf("Else! g_ifcount=%d otherCaseDone=%d\n",g_ifcount,otherCaseDone());
2166 if (g_ifcount==0 && !otherCaseDone())
2173 <SkipCommand>("elif"|"else"{B}*"if")/[ \t(!] {
2176 if (!otherCaseDone())
2178 g_guardExpr.resize(0);
2179 g_lastGuardName.resize(0);
2184 BEGIN(SkipCPPBlock);
2188 <SkipCommand>"endif" {
2189 g_expectGuard = FALSE;
2200 BEGIN(SkipCPPBlock);
2202 <SkipCommand>{ID} { // unknown directive
2207 <SkipLine>{CHARLIT} { }
2212 <SkipString>"//"/[^\n]* {
2214 <SkipLine,SkipCommand,SkipCPPBlock>"//"[^\n]* {
2215 g_lastCPPContext=YY_START;
2216 BEGIN(RemoveCPPComment);
2218 <SkipString>"/*"/[^\n]* {
2220 <SkipLine,SkipCommand,SkipCPPBlock>"/*"/[^\n]* {
2221 g_lastCContext=YY_START;
2222 BEGIN(RemoveCComment);
2227 BEGIN(SkipCPPBlock);
2229 <SkipString>[^"\\\n]+ { }
2235 <IncludeID>{ID}{B}*/"(" {
2238 g_defArgsStr=yytext;
2239 g_findDefArgContext = IncludeID;
2240 BEGIN(FindDefineArgs);
2244 readIncludeFile(expandMacro(yytext));
2247 <Include>[^\">\n]+[\">] {
2249 readIncludeFile(g_incName);
2259 <EndImport>[^\\\n]*/\n {
2262 <EndImport>\\[\r]?"\n" {
2268 <DefName>{ID}/("\\\n")*"(" { // define with argument
2269 //printf("Define() `%s'\n",yytext);
2270 g_argDict = new QDict<int>(31);
2271 g_argDict->setAutoDelete(TRUE);
2273 g_defArgsStr.resize(0);
2274 g_defText.resize(0);
2275 g_defLitText.resize(0);
2277 g_defVarArgs = FALSE;
2278 g_defExtraSpacing.resize(0);
2281 <DefName>{ID}{B}+"1"/[ \r\t\n] { // special case: define with 1 -> can be "guard"
2282 //printf("Define `%s'\n",yytext);
2285 g_defArgsStr.resize(0);
2287 g_defName = g_defName.left(g_defName.length()-1).stripWhiteSpace();
2288 g_defVarArgs = FALSE;
2289 //printf("Guard check: %s!=%s || %d\n",
2290 // g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2291 if ( g_defName!=g_lastGuardName || !g_expectGuard)
2292 { // define may appear in the output
2293 QCString tmp=(QCString)"#define "+g_defName;
2294 outputArray(tmp.data(),tmp.length());
2296 g_insideComment=FALSE;
2297 g_lastGuardName.resize(0);
2302 else // define is a guard => hide
2304 //printf("Found a guard %s\n",yytext);
2305 g_defText.resize(0);
2306 g_defLitText.resize(0);
2309 g_expectGuard=FALSE;
2311 <DefName>{ID}/{B}*"\n" { // empty define
2315 g_defArgsStr.resize(0);
2316 g_defText.resize(0);
2317 g_defLitText.resize(0);
2318 g_defVarArgs = FALSE;
2319 //printf("Guard check: %s!=%s || %d\n",
2320 // g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2321 if ( g_defName!=g_lastGuardName || !g_expectGuard)
2322 { // define may appear in the output
2323 QCString tmp=(QCString)"#define "+g_defName;
2324 outputArray(tmp.data(),tmp.length());
2326 g_insideComment=FALSE;
2327 if (g_insideCS) g_defText="1"; // for C#, use "1" as define text
2330 else // define is a guard => hide
2332 //printf("Found a guard %s\n",yytext);
2333 g_guardName = yytext;
2334 g_lastGuardName.resize(0);
2337 g_expectGuard=FALSE;
2339 <DefName>{ID}/{B}* { // define with content
2340 //printf("Define `%s'\n",yytext);
2343 g_defArgsStr.resize(0);
2344 g_defText.resize(0);
2345 g_defLitText.resize(0);
2347 g_defVarArgs = FALSE;
2348 QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr;
2349 outputArray(tmp.data(),tmp.length());
2351 g_insideComment=FALSE;
2355 g_defExtraSpacing+="\n";
2358 <DefineArg>","{B}* { g_defArgsStr+=yytext; }
2359 <DefineArg>"("{B}* { g_defArgsStr+=yytext; }
2360 <DefineArg>{B}*")"{B}* {
2361 g_defArgsStr+=yytext;
2362 QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr+g_defExtraSpacing;
2363 outputArray(tmp.data(),tmp.length());
2365 g_insideComment=FALSE;
2368 <DefineArg>"..." { // Variadic macro
2369 g_defVarArgs = TRUE;
2370 g_defArgsStr+=yytext;
2371 g_argDict->insert("__VA_ARGS__",new int(g_defArgs));
2374 <DefineArg>{ID}{B}*("..."?) {
2375 //printf("Define addArg(%s)\n",yytext);
2376 QCString argName=yytext;
2377 g_defVarArgs = yytext[yyleng-1]=='.';
2378 if (g_defVarArgs) // strip ellipsis
2380 argName=argName.left(argName.length()-3);
2382 argName = argName.stripWhiteSpace();
2383 g_defArgsStr+=yytext;
2384 g_argDict->insert(argName,new int(g_defArgs));
2388 <DefineText>"/ **"|"/ *!" {
2390 g_defLitText+=yytext;
2391 g_insideComment=TRUE;
2395 g_defLitText+=yytext;
2396 g_insideComment=FALSE;
2399 <DefineText>"/*"[!*]? {
2401 g_defLitText+=yytext;
2402 g_lastCContext=YY_START;
2404 BEGIN(CopyCComment);
2406 <DefineText>"//"[!/]? {
2407 outputArray(yytext,yyleng);
2408 g_lastCPPContext=YY_START;
2410 BEGIN(SkipCPPComment);
2412 <SkipCComment>[/]?"*/" {
2413 if (yytext[0]=='/') outputChar('/');
2414 outputChar('*');outputChar('/');
2415 if (--g_commentCount<=0)
2417 if (g_lastCContext==Start)
2418 // small hack to make sure that ^... rule will
2419 // match when going to Start... Example: "/*...*/ some stuff..."
2421 YY_CURRENT_BUFFER->yy_at_bol=1;
2423 BEGIN(g_lastCContext);
2426 <SkipCComment>"//"("/")* {
2427 outputArray(yytext,yyleng);
2429 <SkipCComment>"/*" {
2430 outputChar('/');outputChar('*');
2433 <SkipCComment>[\\@][\\@]("f{"|"f$"|"f[") {
2434 outputArray(yytext,yyleng);
2436 <SkipCComment>[\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly"|"dot"|"code"){BN}+ {
2437 outputArray(yytext,yyleng);
2438 g_yyLineNr+=QCString(yytext).contains('\n');
2440 <SkipCComment>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly"|"dot"|"code"){BN}+ {
2441 outputArray(yytext,yyleng);
2442 g_yyLineNr+=QCString(yytext).contains('\n');
2449 g_blockName=QCString(&yytext[1]).stripWhiteSpace();
2451 BEGIN(SkipVerbatim);
2453 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t]+ { // conditional section
2454 g_condCtx = YY_START;
2455 outputArray(yytext,yyleng);
2458 <CondLine>[a-z_A-Z][a-z_A-Z0-9.\-]* {
2459 startCondSection(yytext);
2460 outputArray(yytext,yyleng);
2463 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t\r]*/\n {
2464 g_condCtx = YY_START;
2465 outputArray(yytext,yyleng);
2469 startCondSection(" ");
2472 <SkipCComment,SkipCPPComment>[\\@]"endcond"/[^a-z_A-Z0-9] {
2473 outputArray(yytext,yyleng);
2476 <SkipVerbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}") { /* end of verbatim block */
2477 outputArray(yytext,yyleng);
2478 if (yytext[1]=='f' && g_blockName=="f")
2480 BEGIN(SkipCComment);
2482 else if (&yytext[4]==g_blockName)
2484 BEGIN(SkipCComment);
2487 <SkipVerbatim>"*/"|"/*" {
2488 outputArray(yytext,yyleng);
2490 <SkipCComment,SkipVerbatim>[^*\\@\x06\n\/]+ {
2491 outputArray(yytext,yyleng);
2493 <SkipCComment,SkipVerbatim>\n {
2497 <SkipCComment,SkipVerbatim>. {
2498 outputChar(*yytext);
2500 <CopyCComment>[^*a-z_A-Z\n]+ {
2501 g_defLitText+=yytext;
2502 g_defText+=escapeAt(yytext);
2504 <CopyCComment>"*/" {
2505 g_defLitText+=yytext;
2507 BEGIN(g_lastCContext);
2511 g_defLitText+=yytext;
2514 <RemoveCComment>"*/"{B}*"#" { // see bug 594021 for a usecase for this rule
2515 if (g_lastCContext==SkipCPPBlock)
2524 <RemoveCComment>"*/" { BEGIN(g_lastCContext); }
2525 <RemoveCComment>"//"
2526 <RemoveCComment>"/*"
2527 <RemoveCComment>[^*\x06\n]+
2528 <RemoveCComment>\n { g_yyLineNr++; outputChar('\n'); }
2530 <SkipCPPComment>[^\n\/\\@]+ {
2531 outputArray(yytext,yyleng);
2533 <SkipCPPComment,RemoveCPPComment>\n {
2535 BEGIN(g_lastCPPContext);
2537 <SkipCPPComment>"/*" {
2538 outputChar('/');outputChar('*');
2540 <SkipCPPComment>"//" {
2541 outputChar('/');outputChar('/');
2543 <SkipCPPComment>[^\x06\@\\\n]+ {
2544 outputArray(yytext,yyleng);
2547 outputChar(*yytext);
2549 <RemoveCPPComment>"/*"
2550 <RemoveCPPComment>"//"
2551 <RemoveCPPComment>[^\x06\n]+
2555 g_defLitText+=yytext;
2557 <DefineText,CopyCComment>{ID} {
2558 g_defLitText+=yytext;
2566 if ((n=(*g_argDict)[yytext]))
2568 //if (!g_quoteArg) g_defText+=' ';
2571 numStr.sprintf("%d",*n);
2573 //if (!g_quoteArg) g_defText+=' ';
2591 g_defLitText+=yytext;
2594 <DefineText>\\[\r]?\n {
2595 g_defLitText+=yytext;
2597 g_defText += ' '; g_yyLineNr++;
2600 QCString comment=extractTrailingComment(g_defLitText);
2601 g_defLitText+=yytext;
2602 if (!comment.isEmpty())
2604 outputArray(comment,comment.length());
2605 g_defLitText=g_defLitText.left(g_defLitText.length()-comment.length()-1);
2609 //printf("Define name=`%s' text=`%s' litTexti=`%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data());
2610 if (g_includeStack.isEmpty() || g_curlyCount>0)
2614 def=DefineManager::instance().isDefined(g_defName);
2615 if (def==0) // new define
2617 //printf("new define '%s'!\n",g_defName.data());
2618 Define *nd = newDefine();
2619 DefineManager::instance().addDefine(g_yyFileName,nd);
2621 // also add it to the local file list if it is a source file
2622 //if (g_isSource && g_includeStack.isEmpty())
2624 // g_fileDefineDict->insert(g_defName,nd);
2627 else if (def /*&& macroIsAccessible(def)*/)
2628 // name already exists
2630 //printf("existing define!\n");
2631 //printf("define found\n");
2632 if (def->undef) // undefined name
2635 def->name = g_defName;
2636 def->definition = g_defText.stripWhiteSpace();
2637 def->nargs = g_defArgs;
2638 def->fileName = g_yyFileName.copy();
2639 def->lineNr = g_yyLineNr;
2643 //printf("error: define %s is defined more than once!\n",g_defName.data());
2646 delete g_argDict; g_argDict=0;
2648 g_lastGuardName.resize(0);
2651 <DefineText>{B}* { g_defText += ' '; g_defLitText+=yytext; }
2652 <DefineText>{B}*"##"{B}* { g_defText += "##"; g_defLitText+=yytext; }
2653 <DefineText>"@" { g_defText += "@@"; g_defLitText+=yytext; }
2655 g_defText += *yytext;
2656 g_defLitText+=yytext;
2657 if (!g_insideComment)
2659 BEGIN(SkipDoubleQuote);
2662 <DefineText>\' { g_defText += *yytext;
2663 g_defLitText+=yytext;
2664 if (!g_insideComment)
2666 BEGIN(SkipSingleQuote);
2669 <SkipDoubleQuote>"//"[/]? { g_defText += yytext; g_defLitText+=yytext; }
2670 <SkipDoubleQuote>"/*" { g_defText += yytext; g_defLitText+=yytext; }
2671 <SkipDoubleQuote>\" {
2672 g_defText += *yytext; g_defLitText+=yytext;
2675 <SkipSingleQuote,SkipDoubleQuote>\\. {
2676 g_defText += yytext; g_defLitText+=yytext;
2678 <SkipSingleQuote>\' {
2679 g_defText += *yytext; g_defLitText+=yytext;
2682 <SkipDoubleQuote>. { g_defText += *yytext; g_defLitText+=yytext; }
2683 <SkipSingleQuote>. { g_defText += *yytext; g_defLitText+=yytext; }
2684 <DefineText>. { g_defText += *yytext; g_defLitText+=yytext; }
2686 //fprintf(stderr,"End of include file\n");
2687 //printf("Include stack depth=%d\n",g_includeStack.count());
2688 if (g_includeStack.isEmpty())
2690 //fprintf(stderr,"Terminating scanner!\n");
2695 FileState *fs=g_includeStack.pop();
2696 //fileDefineCache->merge(g_yyFileName,fs->fileName);
2697 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
2698 yy_switch_to_buffer( fs->bufState );
2699 yy_delete_buffer( oldBuf );
2700 g_yyLineNr = fs->lineNr;
2701 //preYYin = fs->oldYYin;
2702 g_inputBuf = fs->oldFileBuf;
2703 g_inputBufPos = fs->oldFileBufPos;
2704 setFileName(fs->fileName);
2705 //fprintf(stderr,"######## FileName %s\n",g_yyFileName.data());
2707 // Deal with file changes due to
2708 // #include's within { .. } blocks
2709 QCString lineStr(15+g_yyFileName.length());
2710 lineStr.sprintf("# %d \"%s\" 2",g_yyLineNr,g_yyFileName.data());
2711 outputArray(lineStr.data(),lineStr.length());
2718 outputArray(yytext,yyleng);
2719 g_lastCContext=YY_START;
2721 if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2722 BEGIN(SkipCComment);
2725 outputArray(yytext,yyleng);
2726 g_lastCPPContext=YY_START;
2727 if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2728 BEGIN(SkipCPPComment);
2735 g_expectGuard = FALSE;
2736 outputChar(*yytext);
2741 /*@ ----------------------------------------------------------------------------
2744 static int getNextChar(const QCString &expr,QCString *rest,uint &pos)
2746 //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2747 if (pos<expr.length())
2749 //printf("%c=expr()\n",expr.at(pos));
2750 return expr.at(pos++);
2752 else if (rest && !rest->isEmpty())
2755 *rest=rest->right(rest->length()-1);
2756 //printf("%c=rest\n",cc);
2762 //printf("%c=yyinput()\n",cc);
2767 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos)
2769 //printf("getCurrentChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2770 if (pos<expr.length())
2772 //printf("%c=expr()\n",expr.at(pos));
2773 return expr.at(pos);
2775 else if (rest && !rest->isEmpty())
2778 //printf("%c=rest\n",cc);
2784 returnCharToStream(cc);
2786 //printf("%c=yyinput()\n",cc);
2791 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c)
2793 //printf("unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2794 if (pos<expr.length())
2800 //printf("Prepending to rest!\n");
2801 char cs[2];cs[0]=c;cs[1]='\0';
2807 returnCharToStream(c);
2809 //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2812 void addSearchDir(const char *dir)
2815 if (fi.isDir()) g_pathList->append(fi.absFilePath().utf8());
2818 void initPreprocessor()
2820 g_pathList = new QStrList;
2822 g_expandedDict = new DefineDict(17);
2825 void cleanUpPreprocessor()
2827 delete g_expandedDict; g_expandedDict=0;
2828 delete g_pathList; g_pathList=0;
2829 DefineManager::deleteInstance();
2833 void preprocessFile(const char *fileName,BufStr &input,BufStr &output)
2835 uint orgOffset=output.curPos();
2836 //printf("##########################\n%s\n####################\n",
2839 g_macroExpansion = Config_getBool("MACRO_EXPANSION");
2840 g_expandOnlyPredef = Config_getBool("EXPAND_ONLY_PREDEF");
2845 g_outputBuf=&output;
2846 g_includeStack.setAutoDelete(TRUE);
2847 g_includeStack.clear();
2848 g_expandedDict->setAutoDelete(FALSE);
2849 g_expandedDict->clear();
2850 g_condStack.clear();
2851 g_condStack.setAutoDelete(TRUE);
2852 //g_fileDefineDict->clear();
2854 setFileName(fileName);
2855 g_inputFileDef = g_yyFileDef;
2856 DefineManager::instance().startContext(g_yyFileName);
2858 static bool firstTime=TRUE;
2861 // add predefined macros
2863 QStrList &predefList = Config_getList("PREDEFINED");
2864 QStrListIterator sli(predefList);
2865 for (sli.toFirst();(defStr=sli.current());++sli)
2867 QCString ds = defStr;
2868 int i_equals=ds.find('=');
2869 int i_obrace=ds.find('(');
2870 int i_cbrace=ds.find(')');
2871 bool nonRecursive = i_equals>0 && ds.at(i_equals-1)==':';
2873 if (i_obrace==0) continue; // no define name
2875 if (i_obrace<i_equals && i_cbrace<i_equals &&
2876 i_obrace!=-1 && i_cbrace!=-1 &&
2878 ) // predefined function macro definition
2880 //printf("predefined function macro '%s'\n",defStr);
2881 QRegExp reId("[a-z_A-Z][a-z_A-Z0-9]*"); // regexp matching an id
2882 QDict<int> argDict(17);
2883 argDict.setAutoDelete(TRUE);
2884 int i=i_obrace+1,p,l,count=0;
2885 // gather the formal arguments in a dictionary
2886 while (i<i_cbrace && (p=reId.match(ds,i,&l)))
2888 argDict.insert(ds.mid(p,l),new int(count++));
2891 // strip definition part
2892 QCString tmp=ds.right(ds.length()-i_equals-1);
2893 QCString definition;
2895 // substitute all occurrences of formal arguments by their
2896 // corresponding markers
2897 while ((p=reId.match(tmp,i,&l))!=-1)
2899 if (p>i) definition+=tmp.mid(i,p-i);
2901 if ((argIndex=argDict[tmp.mid(p,l)])!=0)
2904 marker.sprintf(" @%d ",*argIndex);
2909 definition+=tmp.mid(p,l);
2913 if (i<(int)tmp.length()) definition+=tmp.mid(i,tmp.length()-i);
2915 // add define definition to the dictionary of defines for this file
2916 QCString dname = ds.left(i_obrace);
2917 if (!dname.isEmpty())
2919 Define *def = new Define;
2921 def->definition = definition;
2923 def->isPredefined = TRUE;
2924 def->nonRecursive = nonRecursive;
2925 def->fileDef = g_yyFileDef;
2926 def->fileName = fileName;
2927 DefineManager::instance().addDefine(g_yyFileName,def);
2930 //printf("#define `%s' `%s' #nargs=%d\n",
2931 // def->name.data(),def->definition.data(),def->nargs);
2933 else if ((i_obrace==-1 || i_obrace>i_equals) &&
2934 (i_cbrace==-1 || i_cbrace>i_equals) &&
2935 !ds.isEmpty() && (int)ds.length()>i_equals
2936 ) // predefined non-function macro definition
2938 //printf("predefined normal macro '%s'\n",defStr);
2939 Define *def = new Define;
2940 if (i_equals==-1) // simple define without argument
2943 def->definition = "1"; // substitute occurrences by 1 (true)
2945 else // simple define with argument
2947 int ine=i_equals - (nonRecursive ? 1 : 0);
2948 def->name = ds.left(ine);
2949 def->definition = ds.right(ds.length()-i_equals-1);
2951 if (!def->name.isEmpty())
2954 def->isPredefined = TRUE;
2955 def->nonRecursive = nonRecursive;
2956 def->fileDef = g_yyFileDef;
2957 def->fileName = fileName;
2958 DefineManager::instance().addDefine(g_yyFileName,def);
2965 //printf("#define `%s' `%s' #nargs=%d\n",
2966 // def->name.data(),def->definition.data(),def->nargs);
2978 g_expectGuard = guessSection(fileName)==Entry::HEADER_SEC;
2979 g_guardName.resize(0);
2980 g_lastGuardName.resize(0);
2981 g_guardExpr.resize(0);
2986 // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829)
2987 forceEndCondSection();
2989 // remove locally defined macros so they can be redefined in another source file
2990 //if (g_fileDefineDict->count()>0)
2992 // QDictIterator<Define> di(*g_fileDefineDict);
2994 // for (di.toFirst();(d=di.current());++di)
2996 // g_globalDefineDict->remove(di.currentKey());
2998 // g_fileDefineDict->clear();
3001 if (Debug::isFlagSet(Debug::Preprocessor))
3003 char *orgPos=output.data()+orgOffset;
3004 char *newPos=output.data()+output.curPos();
3005 Debug::print(Debug::Preprocessor,0,"Preprocessor output (size: %d bytes):\n",newPos-orgPos);
3007 Debug::print(Debug::Preprocessor,0,"---------\n00001 ");
3008 while (orgPos<newPos)
3011 if (*orgPos=='\n') Debug::print(Debug::Preprocessor,0,"%05d ",++line);
3014 Debug::print(Debug::Preprocessor,0,"\n---------\n");
3015 if (DefineManager::instance().defineContext().count()>0)
3017 Debug::print(Debug::Preprocessor,0,"Macros accessible in this file:\n");
3018 Debug::print(Debug::Preprocessor,0,"---------\n");
3019 QDictIterator<Define> di(DefineManager::instance().defineContext());
3021 for (di.toFirst();(def=di.current());++di)
3023 Debug::print(Debug::Preprocessor,0,"%s ",def->name.data());
3025 Debug::print(Debug::Preprocessor,0,"\n---------\n");
3029 Debug::print(Debug::Preprocessor,0,"No macros accessible in this file.\n");
3032 DefineManager::instance().endContext();
3035 void preFreeScanner()
3037 #if defined(YY_FLEX_SUBMINOR_VERSION)
3045 #if !defined(YY_FLEX_SUBMINOR_VERSION)
3046 extern "C" { // some bogus code to keep the compiler happy
3047 // int preYYwrap() { return 1 ; }
3048 void preYYdummy() { yy_flex_realloc(0,0); }