1 /******************************************************************************
5 * Copyright (C) 1997-2015 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.
17 %option never-interactive
18 %option prefix="preYY"
37 #include <qfileinfo.h>
51 #include "arguments.h"
53 #include "condparser.h"
56 #include "memberdef.h"
57 #include "membername.h"
59 #define YY_NO_UNISTD_H 1
61 // Toggle for some debugging info
62 //#define DBG_CTX(x) fprintf x
63 #define DBG_CTX(x) do { } while(0)
67 CondCtx(int line,QCString id,bool b)
68 : lineNr(line),sectionId(id), skip(b) {}
76 FileState(int size) : lineNr(1), fileBuf(size),
77 oldFileBuf(0), oldFileBufPos(0), bufState(0) {}
82 YY_BUFFER_STATE bufState;
86 /** @brief Singleton that manages the defines available while
87 * proprocessing files.
91 /** Local class used to hold the defines for a single file */
95 /** Creates an empty container for defines */
96 DefinesPerFile() : m_defines(257), m_includedFiles(17)
98 m_defines.setAutoDelete(TRUE);
100 /** Destroys the object */
101 virtual ~DefinesPerFile()
104 /** Adds a define in the context of a file. Will replace
105 * an existing define with the same name (redefinition)
106 * @param def The Define object to add.
108 void addDefine(Define *def)
110 Define *d = m_defines.find(def->name);
111 if (d!=0) // redefine
113 m_defines.remove(d->name);
115 m_defines.insert(def->name,def);
117 /** Adds an include file for this file
118 * @param fileName The name of the include file
120 void addInclude(const char *fileName)
122 m_includedFiles.insert(fileName,(void*)0x8);
124 void collectDefines(DefineDict *dict,QDict<void> &includeStack);
126 DefineDict m_defines;
127 QDict<void> m_includedFiles;
131 friend class DefinesPerFile;
132 /** Returns a reference to the singleton */
133 static DefineManager &instance()
135 if (theInstance==0) theInstance = new DefineManager;
138 /** Deletes the singleton */
139 static void deleteInstance()
144 /** Starts a context in which defines are collected.
145 * Called at the start of a new file that is preprocessed.
146 * @param fileName the name of the file to process.
148 void startContext(const char *fileName)
150 //printf("DefineManager::startContext()\n");
151 m_contextDefines.clear();
152 if (fileName==0) return;
153 DefinesPerFile *dpf = m_fileMap.find(fileName);
156 //printf("New file!\n");
157 dpf = new DefinesPerFile;
158 m_fileMap.insert(fileName,dpf);
161 /** Ends the context started with startContext() freeing any
162 * defines collected within in this context.
166 //printf("DefineManager::endContext()\n");
167 m_contextDefines.clear();
169 /** Add an included file to the current context.
170 * If the file has been pre-processed already, all defines are added
172 * @param fileName The name of the include file to add to the context.
174 void addFileToContext(const char *fileName)
176 if (fileName==0) return;
177 //printf("DefineManager::addFileToContext(%s)\n",fileName);
178 DefinesPerFile *dpf = m_fileMap.find(fileName);
181 //printf("New file!\n");
182 dpf = new DefinesPerFile;
183 m_fileMap.insert(fileName,dpf);
187 //printf("existing file!\n");
188 QDict<void> includeStack(17);
189 dpf->collectDefines(&m_contextDefines,includeStack);
193 /** Add a define to the manager object.
194 * @param fileName The file in which the define was found
195 * @param def The Define object to add.
197 void addDefine(const char *fileName,Define *def)
199 if (fileName==0) return;
200 //printf("DefineManager::addDefine(%s,%s)\n",fileName,def->name.data());
201 Define *d = m_contextDefines.find(def->name);
202 if (d!=0) // redefine
204 m_contextDefines.remove(d->name);
206 m_contextDefines.insert(def->name,def);
208 DefinesPerFile *dpf = m_fileMap.find(fileName);
211 dpf = new DefinesPerFile;
212 m_fileMap.insert(fileName,dpf);
217 /** Add an include relation to the manager object.
218 * @param fromFileName file name in which the include was found.
219 * @param toFileName file name that is included.
221 void addInclude(const char *fromFileName,const char *toFileName)
223 //printf("DefineManager::addInclude(%s,%s)\n",fromFileName,toFileName);
224 if (fromFileName==0 || toFileName==0) return;
225 DefinesPerFile *dpf = m_fileMap.find(fromFileName);
228 dpf = new DefinesPerFile;
229 m_fileMap.insert(fromFileName,dpf);
231 dpf->addInclude(toFileName);
233 /** Returns a Define object given its name or 0 if the Define does
236 Define *isDefined(const char *name) const
238 Define *d = m_contextDefines.find(name);
239 if (d && d->undef) d=0;
240 //printf("isDefined(%s)=%p\n",name,d);
243 /** Returns a reference to the defines found in the current context. */
244 const DefineDict &defineContext() const
246 return m_contextDefines;
249 static DefineManager *theInstance;
251 /** Helper function to collect all define for a given file */
252 void collectDefinesForFile(const char *fileName,DefineDict *dict)
254 if (fileName==0) return;
255 DefinesPerFile *dpf = m_fileMap.find(fileName);
258 QDict<void> includeStack(17);
259 dpf->collectDefines(dict,includeStack);
263 /** Helper function to return the DefinesPerFile object for a given file name. */
264 DefinesPerFile *find(const char *fileName) const
266 if (fileName==0) return 0;
267 return m_fileMap.find(fileName);
270 /** Creates a new DefineManager object */
271 DefineManager() : m_fileMap(1009), m_contextDefines(1009)
273 m_fileMap.setAutoDelete(TRUE);
276 /** Destroys the object */
277 virtual ~DefineManager()
281 QDict<DefinesPerFile> m_fileMap;
282 DefineDict m_contextDefines;
285 /** Singleton instance */
286 DefineManager *DefineManager::theInstance = 0;
288 /** Collects all defines for a file and all files that the file includes.
289 * This function will recursively call itself for each file.
290 * @param dict The dictionary to fill with the defines. A redefine will
291 * replace a previous definition.
292 * @param includeStack The stack of includes, used to stop recursion in
293 * case there is a cyclic include dependency.
295 void DefineManager::DefinesPerFile::collectDefines(
296 DefineDict *dict,QDict<void> &includeStack)
298 //printf("DefinesPerFile::collectDefines #defines=%d\n",m_defines.count());
300 QDictIterator<void> di(m_includedFiles);
301 for (di.toFirst();(di.current());++di)
303 QCString incFile = di.currentKey();
304 DefinesPerFile *dpf = DefineManager::instance().find(incFile);
305 if (dpf && includeStack.find(incFile)==0)
307 //printf(" processing include %s\n",incFile.data());
308 includeStack.insert(incFile,(void*)0x8);
309 dpf->collectDefines(dict,includeStack);
314 QDictIterator<Define> di(m_defines);
316 for (di.toFirst();(def=di.current());++di)
318 Define *d = dict->find(def->name);
319 if (d!=0) // redefine
321 dict->remove(d->name);
323 dict->insert(def->name,def);
324 //printf(" adding define %s\n",def->name.data());
329 /* -----------------------------------------------------------------
334 static int g_yyLineNr = 1;
335 static int g_yyMLines = 1;
336 static int g_yyColNr = 1;
337 static QCString g_yyFileName;
338 static FileDef *g_yyFileDef;
339 static FileDef *g_inputFileDef;
340 static int g_ifcount = 0;
341 static QStrList *g_pathList = 0;
342 static QStack<FileState> g_includeStack;
343 static QDict<int> *g_argDict;
344 static int g_defArgs = -1;
345 static QCString g_defName;
346 static QCString g_defText;
347 static QCString g_defLitText;
348 static QCString g_defArgsStr;
349 static QCString g_defExtraSpacing;
350 static bool g_defVarArgs;
352 static int g_lastCContext;
353 static int g_lastCPPContext;
354 static QArray<int> g_levelGuard;
355 static BufStr *g_inputBuf;
356 static int g_inputBufPos;
357 static BufStr *g_outputBuf;
358 static int g_roundCount;
359 static bool g_quoteArg;
360 static DefineDict *g_expandedDict;
361 static int g_findDefArgContext;
362 static bool g_expectGuard;
363 static QCString g_guardName;
364 static QCString g_lastGuardName;
365 static QCString g_incName;
366 static QCString g_guardExpr;
367 static int g_curlyCount;
368 static bool g_nospaces; // add extra spaces during macro expansion
370 static bool g_macroExpansion; // from the configuration
371 static bool g_expandOnlyPredef; // from the configuration
372 static int g_commentCount;
373 static bool g_insideComment;
374 static bool g_isImported;
375 static QCString g_blockName;
376 static int g_condCtx;
378 static QStack<CondCtx> g_condStack;
379 static bool g_insideCS; // C# has simpler preprocessor
380 static bool g_isSource;
382 static bool g_lexInit = FALSE;
383 static int g_fenceSize = 0;
384 static bool g_ccomment;
386 //DefineDict* getGlobalDefineDict()
388 // return g_globalDefineDict;
391 static void setFileName(const char *name)
395 g_yyFileName=fi.absFilePath().utf8();
396 g_yyFileDef=findFileDef(Doxygen::inputNameDict,g_yyFileName,ambig);
397 if (g_yyFileDef==0) // if this is not an input file check if it is an
400 g_yyFileDef=findFileDef(Doxygen::includeNameDict,g_yyFileName,ambig);
402 //printf("setFileName(%s) g_yyFileName=%s g_yyFileDef=%p\n",
403 // name,g_yyFileName.data(),g_yyFileDef);
404 if (g_yyFileDef && g_yyFileDef->isReference()) g_yyFileDef=0;
405 g_insideCS = getLanguageFromFileName(g_yyFileName)==SrcLangExt_CSharp;
406 g_isSource = guessSection(g_yyFileName);
409 static void incrLevel()
412 g_levelGuard.resize(g_level);
413 g_levelGuard[g_level-1]=FALSE;
414 //printf("%s line %d: incrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level);
417 static void decrLevel()
419 //printf("%s line %d: decrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level);
423 g_levelGuard.resize(g_level);
427 warn(g_yyFileName,g_yyLineNr,"More #endif's than #if's found.\n");
431 static bool otherCaseDone()
435 warn(g_yyFileName,g_yyLineNr,"Found an #else without a preceding #if.\n");
440 return g_levelGuard[g_level-1];
444 static void setCaseDone(bool value)
446 g_levelGuard[g_level-1]=value;
449 static QDict<void> g_allIncludes(10009);
451 static FileState *checkAndOpenFile(const QCString &fileName,bool &alreadyIncluded)
453 alreadyIncluded = FALSE;
455 //printf("checkAndOpenFile(%s)\n",fileName.data());
456 QFileInfo fi(fileName);
457 if (fi.exists() && fi.isFile())
459 static QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
460 if (patternMatch(fi,&exclPatterns)) return 0;
462 QCString absName = fi.absFilePath().utf8();
465 if (g_curlyCount==0) // not #include inside { ... }
467 if (g_allIncludes.find(absName)!=0)
469 alreadyIncluded = TRUE;
470 //printf(" already included 1\n");
471 return 0; // already done
473 g_allIncludes.insert(absName,(void *)0x8);
475 // check include stack for absName
477 QStack<FileState> tmpStack;
478 g_includeStack.setAutoDelete(FALSE);
479 while ((fs=g_includeStack.pop()))
481 if (fs->fileName==absName) alreadyIncluded=TRUE;
484 while ((fs=tmpStack.pop()))
486 g_includeStack.push(fs);
488 g_includeStack.setAutoDelete(TRUE);
492 //printf(" already included 2\n");
495 //printf("#include %s\n",absName.data());
497 fs = new FileState(fi.size()+4096);
498 alreadyIncluded = FALSE;
499 if (!readInputFile(absName,fs->fileBuf))
501 //printf(" error reading\n");
507 fs->oldFileBuf = g_inputBuf;
508 fs->oldFileBufPos = g_inputBufPos;
514 static FileState *findFile(const char *fileName,bool localInclude,bool &alreadyIncluded)
516 //printf("** findFile(%s,%d) g_yyFileName=%s\n",fileName,localInclude,g_yyFileName.data());
517 if (portable_isAbsolutePath(fileName))
519 FileState *fs = checkAndOpenFile(fileName,alreadyIncluded);
522 setFileName(fileName);
526 else if (alreadyIncluded)
531 if (localInclude && !g_yyFileName.isEmpty())
533 QFileInfo fi(g_yyFileName);
536 QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+fileName;
537 FileState *fs = checkAndOpenFile(absName,alreadyIncluded);
540 setFileName(absName);
544 else if (alreadyIncluded)
554 char *s=g_pathList->first();
557 QCString absName = (QCString)s+"/"+fileName;
558 //printf(" Looking for %s in %s\n",fileName,s);
559 FileState *fs = checkAndOpenFile(absName,alreadyIncluded);
562 setFileName(absName);
564 //printf(" -> found it\n");
567 else if (alreadyIncluded)
572 s=g_pathList->next();
577 static QCString extractTrailingComment(const char *s)
589 if (i>=0 && s[i]=='*') // end of a comment block
592 while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--;
597 // only /*!< or /**< are treated as a comment for the macro name,
598 // otherwise the comment is treated as part of the macro definition
599 return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : "";
607 // whitespace or line-continuation
622 static int getNextChar(const QCString &expr,QCString *rest,uint &pos);
623 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos);
624 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c);
625 static void expandExpression(QCString &expr,QCString *rest,int pos);
627 static QCString stringize(const QCString &s)
636 if (!inString && !inChar)
638 while (i<s.length() && !inString && !inChar)
659 while (i<s.length() && inChar)
680 while (i<s.length() && inString)
696 //printf("stringize `%s'->`%s'\n",s.data(),result.data());
700 /*! Execute all ## operators in expr.
701 * If the macro name before or after the operator contains a no-rescan
702 * marker (@-) then this is removed (before the concatenated macro name
703 * may be expanded again.
705 static void processConcatOperators(QCString &expr)
707 //printf("processConcatOperators: in=`%s'\n",expr.data());
708 QRegExp r("[ \\t\\n]*##[ \\t\\n]*");
710 if (expr.isEmpty()) return;
711 while ((n=r.match(expr,i,&l))!=-1)
713 //printf("Match: `%s'\n",expr.data()+i);
714 if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-')
716 // remove no-rescan marker after ID
719 //printf("found `%s'\n",expr.mid(n,l).data());
720 // remove the ## operator and the surrounding whitespace
721 expr=expr.left(n)+expr.right(expr.length()-n-l);
723 while (k>=0 && isId(expr.at(k))) k--;
724 if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@')
726 // remove no-rescan marker before ID
727 expr=expr.left(k-1)+expr.right(expr.length()-k-1);
732 //printf("processConcatOperators: out=`%s'\n",expr.data());
735 static void yyunput (int c,char *buf_ptr );
736 static void returnCharToStream(char c)
741 static inline void addTillEndOfString(const QCString &expr,QCString *rest,
742 uint &pos,char term,QCString &arg)
745 while ((cc=getNextChar(expr,rest,pos))!=EOF && cc!=0)
747 if (cc=='\\') arg+=(char)cc,cc=getNextChar(expr,rest,pos);
748 else if (cc==term) return;
753 /*! replaces the function macro \a def whose argument list starts at
754 * \a pos in expression \a expr.
755 * Notice that this routine may scan beyond the \a expr string if needed.
756 * In that case the characters will be read from the input file.
757 * The replacement string will be returned in \a result and the
758 * length of the (unexpanded) argument list is stored in \a len.
760 static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result)
762 //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);
767 while ((cc=getCurrentChar(expr,rest,j))!=EOF && isspace(cc))
770 getNextChar(expr,rest,j);
774 unputChar(expr,rest,j,' ');
777 getNextChar(expr,rest,j); // eat the `(' character
779 QDict<QCString> argTable; // list of arguments
780 argTable.setAutoDelete(TRUE);
785 // PHASE 1: read the macro arguments
788 while ((cc=getNextChar(expr,rest,j))!=EOF && cc!=0)
796 while (!done && (argCount<def->nargs || def->varArgs) &&
797 ((cc=getNextChar(expr,rest,j))!=EOF && cc!=0)
801 if (c=='(') // argument is a function => search for matching )
806 while ((cc=getNextChar(expr,rest,j))!=EOF && cc!=0)
809 //printf("processing %c: term=%c (%d)\n",c,term,term);
810 if (c=='\'' || c=='\"') // skip ('s and )'s inside strings
813 addTillEndOfString(expr,rest,j,c,arg);
830 else if (c==')' || c==',') // last or next argument found
832 if (c==',' && argCount==def->nargs-1 && def->varArgs)
834 arg=arg.stripWhiteSpace();
840 argKey.sprintf("@%d",argCount++); // key name
841 arg=arg.stripWhiteSpace();
842 // add argument to the lookup table
843 argTable.insert(argKey, new QCString(arg));
845 if (c==')') // end of the argument list
851 else if (c=='\"') // append literal strings
855 while (!found && (cc=getNextChar(expr,rest,j))!=EOF && cc!=0)
862 if ((cc=getNextChar(expr,rest,j))==EOF || cc==0) break;
868 else if (c=='\'') // append literal characters
872 while (!found && (cc=getNextChar(expr,rest,j))!=EOF && cc!=0)
879 if ((cc=getNextChar(expr,rest,j))==EOF || cc==0) break;
885 else // append other characters
892 // PHASE 2: apply the macro function
893 if (argCount==def->nargs || // same number of arguments
894 (argCount>=def->nargs-1 && def->varArgs)) // variadic macro with at least as many
895 // params as the non-variadic part (see bug731985)
898 // substitution of all formal arguments
900 const QCString d=def->definition.stripWhiteSpace();
901 //printf("Macro definition: %s\n",d.data());
905 if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
907 if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
910 resExpr+="@@"; // we unescape these later
912 else if (d.at(k+1)=='-') // no-rescan marker
917 else // argument marker => read the argument number
923 // search for ## backward
924 if (l>=0 && d.at(l)=='"') l--;
925 while (l>=0 && d.at(l)==' ') l--;
926 if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
929 while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
932 // search for ## forward
934 if (l<(int)d.length() && d.at(l)=='"') l++;
935 while (l<(int)d.length() && d.at(l)==' ') l++;
936 if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
938 //printf("request key %s result %s\n",key.data(),argTable[key]->data());
939 if (key.length()>1 && (subst=argTable[key]))
941 QCString substArg=*subst;
942 //printf("substArg=`%s'\n",substArg.data());
943 // only if no ## operator is before or after the argument
944 // marker we do macro expansion.
945 if (!hash) expandExpression(substArg,0,0);
948 //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data());
950 // if the marker is inside a string (because a # was put
951 // before the macro name) we must escape " and \ characters
952 resExpr+=stringize(substArg);
956 if (hash && substArg.isEmpty())
958 resExpr+="@E"; // empty argument will be remove later on
966 resExpr+=" "+substArg+" ";
972 else // no marker, just copy
974 if (!inString && d.at(k)=='\"')
976 inString=TRUE; // entering a literal string
978 else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
980 inString=FALSE; // leaving a literal string
987 //printf("result after substitution `%s' expr=`%s'\n",
988 // result.data(),expr.mid(pos,len).data());
995 /*! returns the next identifier in string \a expr by starting at position \a p.
996 * The position of the identifier is returned (or -1 if nothing is found)
997 * and \a l is its length. Any quoted strings are skipping during the search.
999 static int getNextId(const QCString &expr,int p,int *l)
1002 while (p<(int)expr.length())
1004 char c=expr.at(p++);
1005 if (isdigit(c)) // skip number
1007 while (p<(int)expr.length() && isId(expr.at(p))) p++;
1009 else if (isalpha(c) || c=='_') // read id
1012 while (p<(int)expr.length() && isId(expr.at(p))) p++;
1016 else if (c=='"') // skip string
1019 if (p<(int)expr.length()) c=expr.at(p);
1020 while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\')))
1021 // continue as long as no " is found, but ignoring \", but not \\"
1028 if (p<(int)expr.length()) ++p; // skip closing quote
1030 else if (c=='/') // skip C Comment
1032 //printf("Found C comment at p=%d\n",p);
1034 if (p<(int)expr.length())
1037 if (c=='*') // Start of C comment
1040 while (p<(int)expr.length() && !(pc=='*' && c=='/'))
1047 //printf("Found end of C comment at p=%d\n",p);
1053 /*! performs recursive macro expansion on the string \a expr
1054 * starting at position \a pos.
1055 * May read additional characters from the input while re-scanning!
1056 * If \a expandAll is \c TRUE then all macros in the expression are
1057 * expanded, otherwise only the first is expanded.
1059 static void expandExpression(QCString &expr,QCString *rest,int pos)
1061 //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0);
1064 bool definedTest=FALSE;
1066 while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
1068 bool replaced=FALSE;
1069 macroName=expr.mid(p,l);
1070 //printf("macroName=%s\n",macroName.data());
1071 if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
1073 if (g_expandedDict->find(macroName)==0) // expand macro
1075 Define *def=DefineManager::instance().isDefined(macroName);
1076 if (definedTest) // macro name was found after defined
1078 if (def) expMacro = " 1 "; else expMacro = " 0 ";
1083 else if (def && def->nargs==-1) // simple macro
1085 // substitute the definition of the macro
1086 //printf("macro `%s'->`%s'\n",macroName.data(),def->definition.data());
1089 expMacro=def->definition.stripWhiteSpace();
1093 expMacro=" "+def->definition.stripWhiteSpace()+" ";
1095 //expMacro=def->definition.stripWhiteSpace();
1098 //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data());
1100 else if (def && def->nargs>=0) // function macro
1102 replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro);
1105 else if (macroName=="defined")
1107 //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data());
1111 if (replaced) // expand the macro and rescan the expression
1114 //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data());
1115 QCString resultExpr=expMacro;
1116 QCString restExpr=expr.right(expr.length()-len-p);
1117 processConcatOperators(resultExpr);
1118 if (def && !def->nonRecursive)
1120 g_expandedDict->insert(macroName,def);
1121 expandExpression(resultExpr,&restExpr,0);
1122 g_expandedDict->remove(macroName);
1124 expr=expr.left(p)+resultExpr+restExpr;
1126 //printf("new expression: %s\n",expr.data());
1128 else // move to the next macro name
1130 //printf("moving to the next macro old=%d new=%d\n",i,p+l);
1134 else // move to the next macro name
1136 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
1137 //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data());
1142 else // no re-scan marker found, skip the macro name
1144 //printf("skipping marked macro\n");
1150 /*! replaces all occurrences of @@@@ in \a s by @@
1151 * and removes all occurrences of @@E.
1152 * All identifiers found are replaced by 0L
1154 QCString removeIdsAndMarkers(const char *s)
1156 //printf("removeIdsAndMarkers(%s)\n",s);
1165 if (c=='@') // replace @@ with @ and remove @E
1171 else if (*(p+1)=='E')
1177 else if (isdigit(c)) // number
1183 else if (c=='d' && !inNum) // identifier starting with a `d'
1185 if (qstrncmp(p,"defined ",8)==0 || qstrncmp(p,"defined(",8)==0)
1188 p+=7; // skip defined
1194 while ((c=*p) && isId(c)) p++;
1197 else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
1201 while ((c=*p) && isId(c)) p++;
1202 if (*p=='(') // undefined function macro
1208 if (c=='(') count++;
1212 if (count==0) break;
1218 if (c=='*') // start of C comment
1220 while (*p && !(pc=='*' && c=='/')) // search end of comment
1231 else if (c=='/') // skip C comments
1235 if (c=='*') // start of C comment
1237 while (*p && !(pc=='*' && c=='/')) // search end of comment
1244 else // oops, not comment but division
1255 if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE;
1260 //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data());
1264 /*! replaces all occurrences of @@ in \a s by @
1266 * \a s only contains pairs of @@'s
1268 QCString removeMarkers(const char *s)
1279 case '@': // replace @@ with @
1288 case '/': // skip C comments
1293 if (c=='*') // start of C comment
1295 while (*p && !(pc=='*' && c=='/')) // search end of comment
1297 if (*p=='@' && *(p+1)=='@')
1304 if (*p) result+=c,p++;
1308 case '"': // skip string literals
1313 while (*p && (c!='"' || pc=='\\')) // no end quote
1318 if (*p) result+=c,p++;
1321 case '\'': // skip char literals
1326 while (*p && (c!='\'' || pc=='\\')) // no end quote
1331 if (*p) result+=c,p++;
1343 //printf("RemoveMarkers(%s)=%s\n",s,result.data());
1347 /*! compute the value of the expression in string \a expr.
1348 * If needed the function may read additional characters from the input.
1351 bool computeExpression(const QCString &expr)
1354 expandExpression(e,0,0);
1355 //printf("after expansion `%s'\n",e.data());
1356 e = removeIdsAndMarkers(e);
1357 if (e.isEmpty()) return FALSE;
1358 //printf("parsing `%s'\n",e.data());
1359 return parseconstexp(g_yyFileName,g_yyLineNr,e);
1362 /*! expands the macro definition in \a name
1363 * If needed the function may read additional characters from the input
1366 QCString expandMacro(const QCString &name)
1369 expandExpression(n,0,0);
1371 //printf("expandMacro `%s'->`%s'\n",name.data(),n.data());
1377 Define *def=new Define;
1378 def->name = g_defName;
1379 def->definition = g_defText.stripWhiteSpace();
1380 def->nargs = g_defArgs;
1381 def->fileName = g_yyFileName;
1382 def->fileDef = g_yyFileDef;
1383 def->lineNr = g_yyLineNr-g_yyMLines;
1384 def->columnNr = g_yyColNr;
1385 def->varArgs = g_defVarArgs;
1386 //printf("newDefine: %s %s file: %s\n",def->name.data(),def->definition.data(),
1387 // def->fileDef ? def->fileDef->name().data() : def->fileName.data());
1388 //printf("newDefine: `%s'->`%s'\n",def->name.data(),def->definition.data());
1389 if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name])
1391 def->isPredefined=TRUE;
1398 if (g_skip) return; // do not add this define as it is inside a
1399 // conditional section (cond command) that is disabled.
1400 if (!Doxygen::gatherDefines) return;
1402 //printf("addDefine %s %s\n",g_defName.data(),g_defArgsStr.data());
1403 //ArgumentList *al = new ArgumentList;
1404 //stringToArgumentList(g_defArgsStr,al);
1405 MemberDef *md=new MemberDef(
1406 g_yyFileName,g_yyLineNr-g_yyMLines,g_yyColNr,
1407 "#define",g_defName,g_defArgsStr,0,
1408 Public,Normal,FALSE,Member,MemberType_Define,0,0);
1409 if (!g_defArgsStr.isEmpty())
1411 ArgumentList *argList = new ArgumentList;
1412 //printf("addDefine() g_defName=`%s' g_defArgsStr=`%s'\n",g_defName.data(),g_defArgsStr.data());
1413 stringToArgumentList(g_defArgsStr,argList);
1414 md->setArgumentList(argList);
1416 //printf("Setting initializer for `%s' to `%s'\n",g_defName.data(),g_defText.data());
1417 int l=g_defLitText.find('\n');
1418 if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\")
1420 // strip first line if it only contains a slash
1421 g_defLitText = g_defLitText.right(g_defLitText.length()-l-1);
1425 // align the items on the first line with the items on the second line
1427 const char *p=g_defLitText.data()+k;
1429 while ((c=*p++) && (c==' ' || c=='\t')) k++;
1430 g_defLitText=g_defLitText.mid(l+1,k-l-1)+g_defLitText.stripWhiteSpace();
1432 md->setInitializer(g_defLitText.stripWhiteSpace());
1434 //printf("pre.l: md->setFileDef(%p)\n",g_inputFileDef);
1435 md->setFileDef(g_inputFileDef);
1436 md->setDefinition("#define "+g_defName);
1438 MemberName *mn=Doxygen::functionNameSDict->find(g_defName);
1441 mn = new MemberName(g_defName);
1442 Doxygen::functionNameSDict->append(g_defName,mn);
1447 g_yyFileDef->insertMember(md);
1451 //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine());
1454 static inline void outputChar(char c)
1456 if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addChar(c);
1459 static inline void outputArray(const char *a,int len)
1461 if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addArray(a,len);
1464 static void readIncludeFile(const QCString &inc)
1466 static bool searchIncludes = Config_getBool(SEARCH_INCLUDES);
1469 // find the start of the include file name
1470 while (i<inc.length() &&
1471 (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
1475 // was it a local include?
1476 bool localInclude = s>0 && inc.at(s-1)=='"';
1478 // find the end of the include file name
1479 while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
1481 if (s<inc.length() && i>s) // valid include file name found
1483 // extract include path+name
1484 QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
1486 QCString dosExt = incFileName.right(4);
1487 if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb")
1489 // skip imported binary files (e.g. M$ type libraries)
1493 QCString oldFileName = g_yyFileName;
1494 FileDef *oldFileDef = g_yyFileDef;
1495 int oldLineNr = g_yyLineNr;
1496 //printf("Searching for `%s'\n",incFileName.data());
1498 // absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336)
1499 QCString absIncFileName = incFileName;
1501 QFileInfo fi(g_yyFileName);
1504 QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName;
1505 QFileInfo fi2(absName);
1508 absIncFileName=fi2.absFilePath().utf8();
1510 else if (searchIncludes) // search in INCLUDE_PATH as well
1512 QStrList &includePath = Config_getList(INCLUDE_PATH);
1513 char *s=includePath.first();
1517 if (fi.exists() && fi.isDir())
1519 QCString absName = QCString(fi.absFilePath().utf8())+"/"+incFileName;
1520 //printf("trying absName=%s\n",absName.data());
1521 QFileInfo fi2(absName);
1524 absIncFileName=fi2.absFilePath().utf8();
1527 //printf( "absIncFileName = %s\n", absIncFileName.data() );
1529 s=includePath.next();
1532 //printf( "absIncFileName = %s\n", absIncFileName.data() );
1535 DefineManager::instance().addInclude(g_yyFileName,absIncFileName);
1536 DefineManager::instance().addFileToContext(absIncFileName);
1538 // findFile will overwrite g_yyFileDef if found
1540 bool alreadyIncluded = FALSE;
1541 //printf("calling findFile(%s)\n",incFileName.data());
1542 if ((fs=findFile(incFileName,localInclude,alreadyIncluded))) // see if the include file can be found
1544 //printf("Found include file!\n");
1545 if (Debug::isFlagSet(Debug::Preprocessor))
1547 for (i=0;i<g_includeStack.count();i++)
1549 Debug::print(Debug::Preprocessor,0," ");
1551 //msg("#include %s: parsing...\n",incFileName.data());
1555 // add include dependency to the file in which the #include was found
1557 // change to absolute name for bug 641336
1558 FileDef *incFd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1559 oldFileDef->addIncludeDependency(ambig ? 0 : incFd,incFileName,localInclude,g_isImported,FALSE);
1560 // add included by dependency
1563 //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data());
1564 g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1567 else if (g_inputFileDef)
1569 g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1571 fs->bufState = YY_CURRENT_BUFFER;
1572 fs->lineNr = oldLineNr;
1573 fs->fileName = oldFileName;
1574 // push the state on the stack
1575 g_includeStack.push(fs);
1576 // set the scanner to the include file
1578 // Deal with file changes due to
1579 // #include's within { .. } blocks
1580 QCString lineStr(g_yyFileName.length()+20);
1581 lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data());
1582 outputArray(lineStr.data(),lineStr.length());
1584 DBG_CTX((stderr,"Switching to include file %s\n",incFileName.data()));
1586 g_inputBuf = &fs->fileBuf;
1588 yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE));
1592 //printf(" calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded);
1596 //QCString absPath = incFileName;
1597 //if (QDir::isRelativePath(incFileName))
1599 // absPath = QDir::cleanDirPath(oldFileDef->getPath()+"/"+incFileName);
1600 // //printf("%s + %s -> resolved path %s\n",oldFileDef->getPath().data(),incFileName.data(),absPath.data());
1603 // change to absolute name for bug 641336
1604 FileDef *fd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1605 //printf("%s::findFileDef(%s)=%p\n",oldFileDef->name().data(),incFileName.data(),fd);
1606 // add include dependency to the file in which the #include was found
1607 oldFileDef->addIncludeDependency(ambig ? 0 : fd,incFileName,localInclude,g_isImported,FALSE);
1608 // add included by dependency
1611 //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig);
1612 fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1615 else if (g_inputFileDef)
1617 g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1619 if (Debug::isFlagSet(Debug::Preprocessor))
1621 if (alreadyIncluded)
1623 Debug::print(Debug::Preprocessor,0,"#include %s: already included! skipping...\n",qPrint(incFileName));
1627 Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",qPrint(incFileName));
1629 //printf("error: include file %s not found\n",yytext);
1631 if (g_curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... }
1633 warn(g_yyFileName,g_yyLineNr,"include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data());
1639 /* ----------------------------------------------------------------- */
1641 static void startCondSection(const char *sectId)
1643 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1645 bool expResult = prs.parse(g_yyFileName,g_yyLineNr,sectId);
1646 g_condStack.push(new CondCtx(g_yyLineNr,sectId,g_skip));
1651 //printf(" expResult=%d skip=%d\n",expResult,g_skip);
1654 static void endCondSection()
1656 if (g_condStack.isEmpty())
1662 CondCtx *ctx = g_condStack.pop();
1666 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1669 static void forceEndCondSection()
1671 while (!g_condStack.isEmpty())
1673 delete g_condStack.pop();
1678 static QCString escapeAt(const char *text)
1687 if (c=='@') result+="@@"; else result+=c;
1693 static char resolveTrigraph(char c)
1697 case '=': return '#';
1698 case '/': return '\\';
1699 case '\'': return '^';
1700 case '(': return '[';
1701 case ')': return ']';
1702 case '!': return '|';
1703 case '<': return '{';
1704 case '>': return '}';
1705 case '-': return '~';
1710 /* ----------------------------------------------------------------- */
1713 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
1715 static int yyread(char *buf,int max_size)
1717 int bytesInBuf = g_inputBuf->curPos()-g_inputBufPos;
1718 int bytesToCopy = QMIN(max_size,bytesInBuf);
1719 memcpy(buf,g_inputBuf->data()+g_inputBufPos,bytesToCopy);
1720 g_inputBufPos+=bytesToCopy;
1724 /* ----------------------------------------------------------------- */
1728 ID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
1731 CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
1777 <*>"??"[=/'()!<>-] { // Trigraph
1778 unput(resolveTrigraph(yytext[2]));
1780 <Start>^{B}*"#" { BEGIN(Command); g_yyColNr+=yyleng; g_yyMLines=0;}
1782 outputArray(yytext,(int)yyleng);
1785 <Start>^{B}*[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]+{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors?
1787 for (i=(int)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=(int)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,(int)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,(int)yyleng);
1846 <CopyLine>"'"\\."'" {
1847 outputArray(yytext,(int)yyleng);
1850 outputArray(yytext,(int)yyleng);
1853 outputChar(*yytext);
1854 BEGIN( CopyString );
1857 if (getLanguageFromFileName(g_yyFileName)!=SrcLangExt_Fortran) REJECT;
1858 outputChar(*yytext);
1859 BEGIN( CopyStringFtn );
1861 <CopyString>[^\"\\\r\n]+ {
1862 outputArray(yytext,(int)yyleng);
1865 outputArray(yytext,(int)yyleng);
1868 outputChar(*yytext);
1871 <CopyStringFtn>[^\'\\\r\n]+ {
1872 outputArray(yytext,(int)yyleng);
1874 <CopyStringFtn>\\. {
1875 outputArray(yytext,(int)yyleng);
1878 outputChar(*yytext);
1881 <CopyLine>{ID}/{BN}{0,80}"(" {
1882 g_expectGuard = FALSE;
1884 //def=g_globalDefineDict->find(yytext);
1885 //def=DefineManager::instance().isDefined(yytext);
1886 //printf("Search for define %s found=%d g_includeStack.isEmpty()=%d "
1887 // "g_curlyCount=%d g_macroExpansion=%d g_expandOnlyPredef=%d "
1888 // "isPreDefined=%d\n",yytext,def ? 1 : 0,
1889 // g_includeStack.isEmpty(),g_curlyCount,g_macroExpansion,g_expandOnlyPredef,
1890 // def ? def->isPredefined : -1
1892 if ((g_includeStack.isEmpty() || g_curlyCount>0) &&
1894 (def=DefineManager::instance().isDefined(yytext)) &&
1895 /*(def->isPredefined || macroIsAccessible(def)) && */
1896 (!g_expandOnlyPredef || def->isPredefined)
1899 //printf("Found it! #args=%d\n",def->nargs);
1901 g_defArgsStr=yytext;
1902 if (def->nargs==-1) // no function macro
1904 QCString result = def->isPredefined ? def->definition : expandMacro(g_defArgsStr);
1905 outputArray(result,result.length());
1907 else // zero or more arguments
1909 g_findDefArgContext = CopyLine;
1910 BEGIN(FindDefineArgs);
1915 outputArray(yytext,(int)yyleng);
1920 if ((g_includeStack.isEmpty() || g_curlyCount>0) &&
1922 (def=DefineManager::instance().isDefined(yytext)) &&
1924 /*(def->isPredefined || macroIsAccessible(def)) &&*/
1925 (!g_expandOnlyPredef || def->isPredefined)
1928 QCString result=def->isPredefined ? def->definition : expandMacro(yytext);
1929 outputArray(result,result.length());
1933 outputArray(yytext,(int)yyleng);
1936 <CopyLine>"\\"\r?/\n { // strip line continuation characters
1939 outputChar(*yytext);
1947 <FindDefineArgs>"(" {
1951 <FindDefineArgs>")" {
1954 if (g_roundCount==0)
1956 QCString result=expandMacro(g_defArgsStr);
1957 //printf("g_defArgsStr=`%s'->`%s'\n",g_defArgsStr.data(),result.data());
1958 if (g_findDefArgContext==CopyLine)
1960 outputArray(result,result.length());
1961 BEGIN(g_findDefArgContext);
1963 else // g_findDefArgContext==IncludeID
1965 readIncludeFile(result);
1972 <FindDefineArgs>")"{B}*"(" {
1973 g_defArgsStr+=yytext;
1976 <FindDefineArgs>{CHARLIT} {
1977 g_defArgsStr+=yytext;
1979 <FindDefineArgs>"/*"[*]? {
1980 g_defArgsStr+=yytext;
1981 BEGIN(ArgCopyCComment);
1983 <FindDefineArgs>\" {
1984 g_defArgsStr+=*yytext;
1988 if (getLanguageFromFileName(g_yyFileName)!=SrcLangExt_Fortran) REJECT;
1989 g_defArgsStr+=*yytext;
1992 <FindDefineArgs>\n {
1997 <FindDefineArgs>"@" {
2001 g_defArgsStr+=*yytext;
2003 <ArgCopyCComment>[^*\n]+ {
2004 g_defArgsStr+=yytext;
2006 <ArgCopyCComment>"*/" {
2007 g_defArgsStr+=yytext;
2008 BEGIN(FindDefineArgs);
2010 <ArgCopyCComment>\n {
2015 <ArgCopyCComment>. {
2016 g_defArgsStr+=yytext;
2019 g_defArgsStr+=*yytext;
2020 BEGIN(FindDefineArgs);
2023 if (getLanguageFromFileName(g_yyFileName)!=SrcLangExt_Fortran) REJECT;
2024 g_defArgsStr+=*yytext;
2025 BEGIN(FindDefineArgs);
2028 <ReadString>"//"|"/*" {
2029 g_defArgsStr+=yytext;
2032 g_defArgsStr+=yytext;
2035 g_defArgsStr+=*yytext;
2037 <Command>("include"|"import"){B}+/{ID} {
2038 g_isImported = yytext[1]=='m';
2039 if (g_macroExpansion)
2042 <Command>("include"|"import"){B}*[<"] {
2043 g_isImported = yytext[1]=='m';
2045 c[0]=yytext[yyleng-1];c[1]='\0';
2049 <Command>("cmake")?"define"{B}+ {
2050 //printf("!!!DefName\n");
2054 <Command>"ifdef"/{B}*"(" {
2056 g_guardExpr.resize(0);
2057 BEGIN(DefinedExpr2);
2059 <Command>"ifdef"/{B}+ {
2060 //printf("Pre.l: ifdef\n");
2062 g_guardExpr.resize(0);
2063 BEGIN(DefinedExpr1);
2065 <Command>"ifndef"/{B}*"(" {
2068 BEGIN(DefinedExpr2);
2070 <Command>"ifndef"/{B}+ {
2073 BEGIN(DefinedExpr1);
2075 <Command>"if"/[ \t(!] {
2077 g_guardExpr.resize(0);
2080 <Command>("elif"|"else"{B}*"if")/[ \t(!] {
2081 if (!otherCaseDone())
2083 g_guardExpr.resize(0);
2089 BEGIN(SkipCPPBlock);
2092 <Command>"else"/[^a-z_A-Z0-9\x80-\xFF] {
2093 //printf("else g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2094 if (otherCaseDone())
2097 BEGIN(SkipCPPBlock);
2102 //g_levelGuard[g_level-1]=TRUE;
2105 <Command>"undef"{B}+ {
2108 <Command>("elif"|"else"{B}*"if")/[ \t(!] {
2109 if (!otherCaseDone())
2111 g_guardExpr.resize(0);
2115 <Command>"endif"/[^a-z_A-Z0-9\x80-\xFF] {
2116 //printf("Pre.l: #endif\n");
2119 <Command,IgnoreLine>\n {
2124 <Command>"pragma"{B}+"once" {
2125 g_expectGuard = FALSE;
2127 <Command>{ID} { // unknown directive
2130 <IgnoreLine>\\[\r]?\n {
2135 <Command>. {g_yyColNr+=yyleng;}
2138 if ((def=DefineManager::instance().isDefined(yytext))
2139 /*&& !def->isPredefined*/
2140 && !def->nonRecursive
2143 //printf("undefining %s\n",yytext);
2153 <Guard>"defined"/{B}*"(" {
2154 BEGIN(DefinedExpr2);
2156 <Guard>"defined"/{B}+ {
2157 BEGIN(DefinedExpr1);
2159 <Guard>{ID} { g_guardExpr+=yytext; }
2160 <Guard>. { g_guardExpr+=*yytext; }
2163 //printf("Guard: `%s'\n",
2164 // g_guardExpr.data());
2165 bool guard=computeExpression(g_guardExpr);
2167 //printf("if g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2175 BEGIN(SkipCPPBlock);
2178 <DefinedExpr1,DefinedExpr2>\\\n { g_yyLineNr++; outputChar('\n'); }
2179 <DefinedExpr1>{ID} {
2180 if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2181 g_guardExpr+=" 1L ";
2183 g_guardExpr+=" 0L ";
2184 g_lastGuardName=yytext;
2187 <DefinedExpr2>{ID} {
2188 if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2189 g_guardExpr+=" 1L ";
2191 g_guardExpr+=" 0L ";
2192 g_lastGuardName=yytext;
2194 <DefinedExpr1,DefinedExpr2>\n { // should not happen, handle anyway
2197 BEGIN(SkipCPPBlock);
2202 <DefinedExpr1,DefinedExpr2>.
2203 <SkipCPPBlock>^{B}*"#" { BEGIN(SkipCommand); }
2204 <SkipCPPBlock>^{B}*/[^#] { BEGIN(SkipLine); }
2205 <SkipCPPBlock>\n { g_yyLineNr++; outputChar('\n'); }
2207 <SkipCommand>"if"(("n")?("def"))?/[ \t(!] {
2210 //printf("#if... depth=%d\n",g_ifcount);
2212 <SkipCommand>"else" {
2213 //printf("Else! g_ifcount=%d otherCaseDone=%d\n",g_ifcount,otherCaseDone());
2214 if (g_ifcount==0 && !otherCaseDone())
2221 <SkipCommand>("elif"|"else"{B}*"if")/[ \t(!] {
2224 if (!otherCaseDone())
2226 g_guardExpr.resize(0);
2227 g_lastGuardName.resize(0);
2232 BEGIN(SkipCPPBlock);
2236 <SkipCommand>"endif" {
2237 g_expectGuard = FALSE;
2248 BEGIN(SkipCPPBlock);
2250 <SkipCommand>{ID} { // unknown directive
2255 <SkipLine>{CHARLIT} { }
2260 <SkipString>"//"/[^\n]* {
2262 <SkipLine,SkipCommand,SkipCPPBlock>"//"[^\n]* {
2263 g_lastCPPContext=YY_START;
2264 BEGIN(RemoveCPPComment);
2266 <SkipString>"/*"/[^\n]* {
2268 <SkipLine,SkipCommand,SkipCPPBlock>"/*"/[^\n]* {
2269 g_lastCContext=YY_START;
2270 BEGIN(RemoveCComment);
2275 BEGIN(SkipCPPBlock);
2277 <SkipString>[^"\\\n]+ { }
2283 <IncludeID>{ID}{B}*/"(" {
2286 g_defArgsStr=yytext;
2287 g_findDefArgContext = IncludeID;
2288 BEGIN(FindDefineArgs);
2292 readIncludeFile(expandMacro(yytext));
2295 <Include>[^\">\n]+[\">] {
2297 readIncludeFile(g_incName);
2307 <EndImport>[^\\\n]*/\n {
2310 <EndImport>\\[\r]?"\n" {
2316 <DefName>{ID}/("\\\n")*"(" { // define with argument
2317 //printf("Define() `%s'\n",yytext);
2319 g_argDict = new QDict<int>(31);
2320 g_argDict->setAutoDelete(TRUE);
2322 g_defArgsStr.resize(0);
2323 g_defText.resize(0);
2324 g_defLitText.resize(0);
2326 g_defVarArgs = FALSE;
2327 g_defExtraSpacing.resize(0);
2330 <DefName>{ID}{B}+"1"/[ \r\t\n] { // special case: define with 1 -> can be "guard"
2331 //printf("Define `%s'\n",yytext);
2332 delete g_argDict; g_argDict=0;
2334 g_defArgsStr.resize(0);
2336 g_defName = g_defName.left(g_defName.length()-1).stripWhiteSpace();
2337 g_defVarArgs = FALSE;
2338 //printf("Guard check: %s!=%s || %d\n",
2339 // g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2340 if (g_curlyCount>0 || g_defName!=g_lastGuardName || !g_expectGuard)
2341 { // define may appear in the output
2342 QCString tmp=(QCString)"#define "+g_defName;
2343 outputArray(tmp.data(),tmp.length());
2345 g_insideComment=FALSE;
2346 g_lastGuardName.resize(0);
2351 else // define is a guard => hide
2353 //printf("Found a guard %s\n",yytext);
2354 g_defText.resize(0);
2355 g_defLitText.resize(0);
2358 g_expectGuard=FALSE;
2360 <DefName>{ID}/{B}*"\n" { // empty define
2361 delete g_argDict; g_argDict=0;
2364 g_defArgsStr.resize(0);
2365 g_defText.resize(0);
2366 g_defLitText.resize(0);
2367 g_defVarArgs = FALSE;
2368 //printf("Guard check: %s!=%s || %d\n",
2369 // g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2370 if (g_curlyCount>0 || g_defName!=g_lastGuardName || !g_expectGuard)
2371 { // define may appear in the output
2372 QCString tmp=(QCString)"#define "+g_defName;
2373 outputArray(tmp.data(),tmp.length());
2375 g_insideComment=FALSE;
2376 if (g_insideCS) g_defText="1"; // for C#, use "1" as define text
2379 else // define is a guard => hide
2381 //printf("Found a guard %s\n",yytext);
2382 g_guardName = yytext;
2383 g_lastGuardName.resize(0);
2386 g_expectGuard=FALSE;
2388 <DefName>{ID}/{B}* { // define with content
2389 //printf("Define `%s'\n",yytext);
2390 delete g_argDict; g_argDict=0;
2392 g_defArgsStr.resize(0);
2393 g_defText.resize(0);
2394 g_defLitText.resize(0);
2396 g_defVarArgs = FALSE;
2397 QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr;
2398 outputArray(tmp.data(),tmp.length());
2400 g_insideComment=FALSE;
2404 g_defExtraSpacing+="\n";
2407 <DefineArg>","{B}* { g_defArgsStr+=yytext; }
2408 <DefineArg>"("{B}* { g_defArgsStr+=yytext; }
2409 <DefineArg>{B}*")"{B}* {
2410 g_defArgsStr+=yytext;
2411 QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr+g_defExtraSpacing;
2412 outputArray(tmp.data(),tmp.length());
2414 g_insideComment=FALSE;
2417 <DefineArg>"..." { // Variadic macro
2418 g_defVarArgs = TRUE;
2419 g_defArgsStr+=yytext;
2420 g_argDict->insert("__VA_ARGS__",new int(g_defArgs));
2423 <DefineArg>{ID}{B}*("..."?) {
2424 //printf("Define addArg(%s)\n",yytext);
2425 QCString argName=yytext;
2426 g_defVarArgs = yytext[yyleng-1]=='.';
2427 if (g_defVarArgs) // strip ellipsis
2429 argName=argName.left(argName.length()-3);
2431 argName = argName.stripWhiteSpace();
2432 g_defArgsStr+=yytext;
2433 g_argDict->insert(argName,new int(g_defArgs));
2437 <DefineText>"/ **"|"/ *!" {
2439 g_defLitText+=yytext;
2440 g_insideComment=TRUE;
2444 g_defLitText+=yytext;
2445 g_insideComment=FALSE;
2448 <DefineText>"/*"[!*]? {
2450 g_defLitText+=yytext;
2451 g_lastCContext=YY_START;
2453 BEGIN(CopyCComment);
2455 <DefineText>"//"[!/]? {
2456 outputArray(yytext,(int)yyleng);
2457 g_lastCPPContext=YY_START;
2459 BEGIN(SkipCPPComment);
2461 <SkipCComment>[/]?"*/" {
2462 if (yytext[0]=='/') outputChar('/');
2463 outputChar('*');outputChar('/');
2464 if (--g_commentCount<=0)
2466 if (g_lastCContext==Start)
2467 // small hack to make sure that ^... rule will
2468 // match when going to Start... Example: "/*...*/ some stuff..."
2470 YY_CURRENT_BUFFER->yy_at_bol=1;
2472 BEGIN(g_lastCContext);
2475 <SkipCComment>"//"("/")* {
2476 outputArray(yytext,(int)yyleng);
2478 <SkipCComment>"/*" {
2479 outputChar('/');outputChar('*');
2482 <SkipCComment>[\\@][\\@]("f{"|"f$"|"f[") {
2483 outputArray(yytext,(int)yyleng);
2485 <SkipCComment>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
2486 static bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
2487 if (!markdownSupport)
2493 outputArray(yytext,(int)yyleng);
2495 BEGIN(SkipVerbatim);
2498 <SkipCComment>^({B}*"*"+)?{B}{0,3}"```"[`]* {
2499 static bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
2500 if (!markdownSupport)
2506 outputArray(yytext,(int)yyleng);
2508 BEGIN(SkipVerbatim);
2511 <SkipCComment>[\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ {
2512 outputArray(yytext,(int)yyleng);
2513 g_yyLineNr+=QCString(yytext).contains('\n');
2515 <SkipCComment>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ {
2516 outputArray(yytext,(int)yyleng);
2517 g_yyLineNr+=QCString(yytext).contains('\n');
2525 QCString bn=&yytext[1];
2526 int i = bn.find('{'); // for \code{.c}
2527 if (i!=-1) bn=bn.left(i);
2528 g_blockName=bn.stripWhiteSpace();
2530 BEGIN(SkipVerbatim);
2532 <SkipCComment,SkipCPPComment>[\\@][\\@]"cond"[ \t]+ { // escaped @cond
2533 outputArray(yytext,(int)yyleng);
2535 <SkipCPPComment>[\\@]"cond"[ \t]+ { // conditional section
2540 <SkipCComment>[\\@]"cond"[ \t]+ { // conditional section
2545 <CondLineC,CondLineCpp>[!()&| \ta-z_A-Z0-9\x80-\xFF.\-]+ {
2546 startCondSection(yytext);
2549 if (YY_START==CondLineC)
2552 outputArray("*/",2);
2566 <CondLineC,CondLineCpp>. { // non-guard character
2568 startCondSection(" ");
2571 if (YY_START==CondLineC)
2574 outputArray("*/",2);
2588 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t\r]*/\n { // no guard
2589 if (YY_START==SkipCComment)
2593 outputArray("*/",2);
2600 startCondSection(" ");
2603 <SkipCond>\n { g_yyLineNr++; outputChar('\n'); }
2605 <SkipCond>[^\/\!*\\@\n]+ { }
2606 <SkipCond>"//"[/!] { g_ccomment=FALSE; }
2607 <SkipCond>"/*"[*!] { g_ccomment=TRUE; }
2608 <SkipCond,SkipCComment,SkipCPPComment>[\\@][\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2611 outputArray(yytext,(int)yyleng);
2614 <SkipCond>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2615 bool oldSkip = g_skip;
2617 if (oldSkip && !g_skip)
2621 outputArray("/** ",4);
2626 <SkipCComment,SkipCPPComment>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2627 bool oldSkip = g_skip;
2629 if (oldSkip && !g_skip)
2634 <SkipVerbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}") { /* end of verbatim block */
2635 outputArray(yytext,(int)yyleng);
2636 if (yytext[1]=='f' && g_blockName=="f")
2638 BEGIN(SkipCComment);
2640 else if (&yytext[4]==g_blockName)
2642 BEGIN(SkipCComment);
2645 <SkipVerbatim>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
2646 outputArray(yytext,(int)yyleng);
2647 if (g_fenceSize==yyleng)
2649 BEGIN(SkipCComment);
2652 <SkipVerbatim>^({B}*"*"+)?{B}{0,3}"```"[`]* {
2653 outputArray(yytext,(int)yyleng);
2654 if (g_fenceSize==yyleng)
2656 BEGIN(SkipCComment);
2659 <SkipVerbatim>"*/"|"/*" {
2660 outputArray(yytext,(int)yyleng);
2662 <SkipCComment,SkipVerbatim>[^*\\@\x06~`\n\/]+ {
2663 outputArray(yytext,(int)yyleng);
2665 <SkipCComment,SkipVerbatim>\n {
2669 <SkipCComment,SkipVerbatim>. {
2670 outputChar(*yytext);
2672 <CopyCComment>[^*a-z_A-Z\x80-\xFF\n]*[^*a-z_A-Z\x80-\xFF\\\n] {
2673 g_defLitText+=yytext;
2674 g_defText+=escapeAt(yytext);
2676 <CopyCComment>\\[\r]?\n {
2677 g_defLitText+=yytext;
2683 <CopyCComment>"*/" {
2684 g_defLitText+=yytext;
2686 BEGIN(g_lastCContext);
2691 g_defLitText+=yytext;
2694 <RemoveCComment>"*/"{B}*"#" { // see bug 594021 for a usecase for this rule
2695 if (g_lastCContext==SkipCPPBlock)
2704 <RemoveCComment>"*/" { BEGIN(g_lastCContext); }
2705 <RemoveCComment>"//"
2706 <RemoveCComment>"/*"
2707 <RemoveCComment>[^*\x06\n]+
2708 <RemoveCComment>\n { g_yyLineNr++; outputChar('\n'); }
2710 <SkipCPPComment>[^\n\/\\@]+ {
2711 outputArray(yytext,(int)yyleng);
2713 <SkipCPPComment,RemoveCPPComment>\n {
2715 BEGIN(g_lastCPPContext);
2717 <SkipCPPComment>"/*" {
2718 outputChar('/');outputChar('*');
2720 <SkipCPPComment>"//" {
2721 outputChar('/');outputChar('/');
2723 <SkipCPPComment>[^\x06\@\\\n]+ {
2724 outputArray(yytext,(int)yyleng);
2727 outputChar(*yytext);
2729 <RemoveCPPComment>"/*"
2730 <RemoveCPPComment>"//"
2731 <RemoveCPPComment>[^\x06\n]+
2735 g_defLitText+=yytext;
2737 <DefineText,CopyCComment>{ID} {
2738 g_defLitText+=yytext;
2746 if ((n=(*g_argDict)[yytext]))
2748 //if (!g_quoteArg) g_defText+=' ';
2751 numStr.sprintf("%d",*n);
2753 //if (!g_quoteArg) g_defText+=' ';
2771 g_defLitText+=yytext;
2774 <DefineText>\\[\r]?\n {
2775 g_defLitText+=yytext;
2782 QCString comment=extractTrailingComment(g_defLitText);
2783 g_defLitText+=yytext;
2784 if (!comment.isEmpty())
2786 outputArray(comment,comment.length());
2787 g_defLitText=g_defLitText.left(g_defLitText.length()-comment.length()-1);
2791 //printf("Define name=`%s' text=`%s' litTexti=`%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data());
2792 if (g_includeStack.isEmpty() || g_curlyCount>0)
2796 def=DefineManager::instance().isDefined(g_defName);
2797 if (def==0) // new define
2799 //printf("new define '%s'!\n",g_defName.data());
2800 Define *nd = newDefine();
2801 DefineManager::instance().addDefine(g_yyFileName,nd);
2803 // also add it to the local file list if it is a source file
2804 //if (g_isSource && g_includeStack.isEmpty())
2806 // g_fileDefineDict->insert(g_defName,nd);
2809 else if (def /*&& macroIsAccessible(def)*/)
2810 // name already exists
2812 //printf("existing define!\n");
2813 //printf("define found\n");
2814 if (def->undef) // undefined name
2817 def->name = g_defName;
2818 def->definition = g_defText.stripWhiteSpace();
2819 def->nargs = g_defArgs;
2820 def->fileName = g_yyFileName.copy();
2821 def->lineNr = g_yyLineNr-g_yyMLines;
2822 def->columnNr = g_yyColNr;
2826 //printf("error: define %s is defined more than once!\n",g_defName.data());
2829 delete g_argDict; g_argDict=0;
2832 g_lastGuardName.resize(0);
2835 <DefineText>{B}* { g_defText += ' '; g_defLitText+=yytext; }
2836 <DefineText>{B}*"##"{B}* { g_defText += "##"; g_defLitText+=yytext; }
2837 <DefineText>"@" { g_defText += "@@"; g_defLitText+=yytext; }
2839 g_defText += *yytext;
2840 g_defLitText+=yytext;
2841 if (!g_insideComment)
2843 BEGIN(SkipDoubleQuote);
2846 <DefineText>\' { g_defText += *yytext;
2847 g_defLitText+=yytext;
2848 if (!g_insideComment)
2850 BEGIN(SkipSingleQuote);
2853 <SkipDoubleQuote>"//"[/]? { g_defText += yytext; g_defLitText+=yytext; }
2854 <SkipDoubleQuote>"/*" { g_defText += yytext; g_defLitText+=yytext; }
2855 <SkipDoubleQuote>\" {
2856 g_defText += *yytext; g_defLitText+=yytext;
2859 <SkipSingleQuote,SkipDoubleQuote>\\. {
2860 g_defText += yytext; g_defLitText+=yytext;
2862 <SkipSingleQuote>\' {
2863 g_defText += *yytext; g_defLitText+=yytext;
2866 <SkipDoubleQuote>. { g_defText += *yytext; g_defLitText+=yytext; }
2867 <SkipSingleQuote>. { g_defText += *yytext; g_defLitText+=yytext; }
2868 <DefineText>. { g_defText += *yytext; g_defLitText+=yytext; }
2870 DBG_CTX((stderr,"End of include file\n"));
2871 //printf("Include stack depth=%d\n",g_includeStack.count());
2872 if (g_includeStack.isEmpty())
2874 DBG_CTX((stderr,"Terminating scanner!\n"));
2879 FileState *fs=g_includeStack.pop();
2880 //fileDefineCache->merge(g_yyFileName,fs->fileName);
2881 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
2882 yy_switch_to_buffer( fs->bufState );
2883 yy_delete_buffer( oldBuf );
2884 g_yyLineNr = fs->lineNr;
2885 //preYYin = fs->oldYYin;
2886 g_inputBuf = fs->oldFileBuf;
2887 g_inputBufPos = fs->oldFileBufPos;
2888 setFileName(fs->fileName);
2889 DBG_CTX((stderr,"######## FileName %s\n",g_yyFileName.data()));
2891 // Deal with file changes due to
2892 // #include's within { .. } blocks
2893 QCString lineStr(15+g_yyFileName.length());
2894 lineStr.sprintf("# %d \"%s\" 2",g_yyLineNr,g_yyFileName.data());
2895 outputArray(lineStr.data(),lineStr.length());
2902 if (YY_START==SkipVerbatim || YY_START==SkipCond)
2908 outputArray(yytext,(int)yyleng);
2909 g_lastCContext=YY_START;
2911 if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2912 BEGIN(SkipCComment);
2916 if (YY_START==SkipVerbatim || YY_START==SkipCond || getLanguageFromFileName(g_yyFileName)==SrcLangExt_Fortran)
2922 outputArray(yytext,(int)yyleng);
2923 g_lastCPPContext=YY_START;
2924 if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2925 BEGIN(SkipCPPComment);
2933 g_expectGuard = FALSE;
2934 outputChar(*yytext);
2939 /*@ ----------------------------------------------------------------------------
2942 static int getNextChar(const QCString &expr,QCString *rest,uint &pos)
2944 //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2945 if (pos<expr.length())
2947 //printf("%c=expr()\n",expr.at(pos));
2948 return expr.at(pos++);
2950 else if (rest && !rest->isEmpty())
2953 *rest=rest->right(rest->length()-1);
2954 //printf("%c=rest\n",cc);
2960 //printf("%d=yyinput() %d\n",cc,EOF);
2965 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos)
2967 //printf("getCurrentChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2968 if (pos<expr.length())
2970 //printf("%c=expr()\n",expr.at(pos));
2971 return expr.at(pos);
2973 else if (rest && !rest->isEmpty())
2976 //printf("%c=rest\n",cc);
2982 returnCharToStream(cc);
2984 //printf("%c=yyinput()\n",cc);
2989 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c)
2991 //printf("unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2992 if (pos<expr.length())
2998 //printf("Prepending to rest!\n");
2999 char cs[2];cs[0]=c;cs[1]='\0';
3005 returnCharToStream(c);
3007 //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
3010 void addSearchDir(const char *dir)
3013 if (fi.isDir()) g_pathList->append(fi.absFilePath().utf8());
3016 void initPreprocessor()
3018 g_pathList = new QStrList;
3020 g_expandedDict = new DefineDict(17);
3023 void cleanUpPreprocessor()
3025 delete g_expandedDict; g_expandedDict=0;
3026 delete g_pathList; g_pathList=0;
3027 DefineManager::deleteInstance();
3031 void preprocessFile(const char *fileName,BufStr &input,BufStr &output)
3033 printlex(yy_flex_debug, TRUE, __FILE__, fileName);
3034 uint orgOffset=output.curPos();
3035 //printf("##########################\n%s\n####################\n",
3038 g_macroExpansion = Config_getBool(MACRO_EXPANSION);
3039 g_expandOnlyPredef = Config_getBool(EXPAND_ONLY_PREDEF);
3045 g_outputBuf=&output;
3046 g_includeStack.setAutoDelete(TRUE);
3047 g_includeStack.clear();
3048 g_expandedDict->setAutoDelete(FALSE);
3049 g_expandedDict->clear();
3050 g_condStack.setAutoDelete(TRUE);
3051 g_condStack.clear();
3052 //g_fileDefineDict->clear();
3054 setFileName(fileName);
3055 g_inputFileDef = g_yyFileDef;
3056 DefineManager::instance().startContext(g_yyFileName);
3058 static bool firstTime=TRUE;
3061 // add predefined macros
3063 QStrList &predefList = Config_getList(PREDEFINED);
3064 QStrListIterator sli(predefList);
3065 for (sli.toFirst();(defStr=sli.current());++sli)
3067 QCString ds = defStr;
3068 int i_equals=ds.find('=');
3069 int i_obrace=ds.find('(');
3070 int i_cbrace=ds.find(')');
3071 bool nonRecursive = i_equals>0 && ds.at(i_equals-1)==':';
3073 if (i_obrace==0) continue; // no define name
3075 if (i_obrace<i_equals && i_cbrace<i_equals &&
3076 i_obrace!=-1 && i_cbrace!=-1 &&
3078 ) // predefined function macro definition
3080 //printf("predefined function macro '%s'\n",defStr);
3081 QRegExp reId("[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*"); // regexp matching an id
3082 QDict<int> argDict(17);
3083 argDict.setAutoDelete(TRUE);
3084 int i=i_obrace+1,p,l,count=0;
3085 // gather the formal arguments in a dictionary
3086 while (i<i_cbrace && (p=reId.match(ds,i,&l)))
3088 if (l>0) // see bug375037
3090 argDict.insert(ds.mid(p,l),new int(count++));
3098 // strip definition part
3099 QCString tmp=ds.right(ds.length()-i_equals-1);
3100 QCString definition;
3102 // substitute all occurrences of formal arguments by their
3103 // corresponding markers
3104 while ((p=reId.match(tmp,i,&l))!=-1)
3106 if (p>i) definition+=tmp.mid(i,p-i);
3108 if ((argIndex=argDict[tmp.mid(p,l)])!=0)
3111 marker.sprintf(" @%d ",*argIndex);
3116 definition+=tmp.mid(p,l);
3120 if (i<(int)tmp.length()) definition+=tmp.mid(i,tmp.length()-i);
3122 // add define definition to the dictionary of defines for this file
3123 QCString dname = ds.left(i_obrace);
3124 if (!dname.isEmpty())
3126 Define *def = new Define;
3128 def->definition = definition;
3130 def->isPredefined = TRUE;
3131 def->nonRecursive = nonRecursive;
3132 def->fileDef = g_yyFileDef;
3133 def->fileName = fileName;
3134 DefineManager::instance().addDefine(g_yyFileName,def);
3137 //printf("#define `%s' `%s' #nargs=%d\n",
3138 // def->name.data(),def->definition.data(),def->nargs);
3140 else if ((i_obrace==-1 || i_obrace>i_equals) &&
3141 (i_cbrace==-1 || i_cbrace>i_equals) &&
3142 !ds.isEmpty() && (int)ds.length()>i_equals
3143 ) // predefined non-function macro definition
3145 //printf("predefined normal macro '%s'\n",defStr);
3146 Define *def = new Define;
3147 if (i_equals==-1) // simple define without argument
3150 def->definition = "1"; // substitute occurrences by 1 (true)
3152 else // simple define with argument
3154 int ine=i_equals - (nonRecursive ? 1 : 0);
3155 def->name = ds.left(ine);
3156 def->definition = ds.right(ds.length()-i_equals-1);
3158 if (!def->name.isEmpty())
3161 def->isPredefined = TRUE;
3162 def->nonRecursive = nonRecursive;
3163 def->fileDef = g_yyFileDef;
3164 def->fileName = fileName;
3165 DefineManager::instance().addDefine(g_yyFileName,def);
3172 //printf("#define `%s' `%s' #nargs=%d\n",
3173 // def->name.data(),def->definition.data(),def->nargs);
3186 g_expectGuard = guessSection(fileName)==Entry::HEADER_SEC;
3187 g_guardName.resize(0);
3188 g_lastGuardName.resize(0);
3189 g_guardExpr.resize(0);
3194 while (!g_condStack.isEmpty())
3196 CondCtx *ctx = g_condStack.pop();
3197 QCString sectionInfo = " ";
3198 if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label %s ",ctx->sectionId.data());
3199 warn(fileName,ctx->lineNr,"Conditional section%sdoes not have "
3200 "a corresponding \\endcond command within this file.",sectionInfo.data());
3203 // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829)
3204 forceEndCondSection();
3206 // remove locally defined macros so they can be redefined in another source file
3207 //if (g_fileDefineDict->count()>0)
3209 // QDictIterator<Define> di(*g_fileDefineDict);
3211 // for (di.toFirst();(d=di.current());++di)
3213 // g_globalDefineDict->remove(di.currentKey());
3215 // g_fileDefineDict->clear();
3218 if (Debug::isFlagSet(Debug::Preprocessor))
3220 char *orgPos=output.data()+orgOffset;
3221 char *newPos=output.data()+output.curPos();
3222 Debug::print(Debug::Preprocessor,0,"Preprocessor output (size: %d bytes):\n",newPos-orgPos);
3224 Debug::print(Debug::Preprocessor,0,"---------\n00001 ");
3225 while (orgPos<newPos)
3228 if (*orgPos=='\n') Debug::print(Debug::Preprocessor,0,"%05d ",++line);
3231 Debug::print(Debug::Preprocessor,0,"\n---------\n");
3232 if (DefineManager::instance().defineContext().count()>0)
3234 Debug::print(Debug::Preprocessor,0,"Macros accessible in this file:\n");
3235 Debug::print(Debug::Preprocessor,0,"---------\n");
3236 QDictIterator<Define> di(DefineManager::instance().defineContext());
3238 for (di.toFirst();(def=di.current());++di)
3240 Debug::print(Debug::Preprocessor,0,"%s ",qPrint(def->name));
3242 Debug::print(Debug::Preprocessor,0,"\n---------\n");
3246 Debug::print(Debug::Preprocessor,0,"No macros accessible in this file.\n");
3249 DefineManager::instance().endContext();
3250 printlex(yy_flex_debug, FALSE, __FILE__, fileName);
3253 void preFreeScanner()
3255 #if defined(YY_FLEX_SUBMINOR_VERSION)
3263 #if !defined(YY_FLEX_SUBMINOR_VERSION)
3264 extern "C" { // some bogus code to keep the compiler happy
3265 // int preYYwrap() { return 1 ; }
3266 void preYYdummy() { yy_flex_realloc(0,0); }