1 /******************************************************************************
5 * Copyright (C) 1997-2014 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.
35 #include <qfileinfo.h>
49 #include "arguments.h"
51 #include "condparser.h"
54 #include "memberdef.h"
55 #include "membername.h"
57 // Toggle for some debugging info
58 //#define DBG_CTX(x) fprintf x
59 #define DBG_CTX(x) do { } while(0)
61 #define YY_NEVER_INTERACTIVE 1
65 CondCtx(int line,QCString id,bool b)
66 : lineNr(line),sectionId(id), skip(b) {}
74 FileState(int size) : fileBuf(size),
75 oldFileBuf(0), oldFileBufPos(0) {}
80 YY_BUFFER_STATE bufState;
84 /** @brief Singleton that manages the defines available while
85 * proprocessing files.
89 /** Local class used to hold the defines for a single file */
93 /** Creates an empty container for defines */
94 DefinesPerFile() : m_defines(257), m_includedFiles(17)
96 m_defines.setAutoDelete(TRUE);
98 /** Destroys the object */
99 virtual ~DefinesPerFile()
102 /** Adds a define in the context of a file. Will replace
103 * an existing define with the same name (redefinition)
104 * @param def The Define object to add.
106 void addDefine(Define *def)
108 Define *d = m_defines.find(def->name);
109 if (d!=0) // redefine
111 m_defines.remove(d->name);
113 m_defines.insert(def->name,def);
115 /** Adds an include file for this file
116 * @param fileName The name of the include file
118 void addInclude(const char *fileName)
120 m_includedFiles.insert(fileName,(void*)0x8);
122 void collectDefines(DefineDict *dict,QDict<void> &includeStack);
124 DefineDict m_defines;
125 QDict<void> m_includedFiles;
129 friend class DefinesPerFile;
130 /** Returns a reference to the singleton */
131 static DefineManager &instance()
133 if (theInstance==0) theInstance = new DefineManager;
136 /** Deletes the singleton */
137 static void deleteInstance()
142 /** Starts a context in which defines are collected.
143 * Called at the start of a new file that is preprocessed.
144 * @param fileName the name of the file to process.
146 void startContext(const char *fileName)
148 //printf("DefineManager::startContext()\n");
149 m_contextDefines.clear();
150 if (fileName==0) return;
151 DefinesPerFile *dpf = m_fileMap.find(fileName);
154 //printf("New file!\n");
155 dpf = new DefinesPerFile;
156 m_fileMap.insert(fileName,dpf);
159 /** Ends the context started with startContext() freeing any
160 * defines collected within in this context.
164 //printf("DefineManager::endContext()\n");
165 m_contextDefines.clear();
167 /** Add an included file to the current context.
168 * If the file has been pre-processed already, all defines are added
170 * @param fileName The name of the include file to add to the context.
172 void addFileToContext(const char *fileName)
174 if (fileName==0) return;
175 //printf("DefineManager::addFileToContext(%s)\n",fileName);
176 DefinesPerFile *dpf = m_fileMap.find(fileName);
179 //printf("New file!\n");
180 dpf = new DefinesPerFile;
181 m_fileMap.insert(fileName,dpf);
185 //printf("existing file!\n");
186 QDict<void> includeStack(17);
187 dpf->collectDefines(&m_contextDefines,includeStack);
191 /** Add a define to the manager object.
192 * @param fileName The file in which the define was found
193 * @param def The Define object to add.
195 void addDefine(const char *fileName,Define *def)
197 if (fileName==0) return;
198 //printf("DefineManager::addDefine(%s,%s)\n",fileName,def->name.data());
199 Define *d = m_contextDefines.find(def->name);
200 if (d!=0) // redefine
202 m_contextDefines.remove(d->name);
204 m_contextDefines.insert(def->name,def);
206 DefinesPerFile *dpf = m_fileMap.find(fileName);
209 dpf = new DefinesPerFile;
214 /** Add an include relation to the manager object.
215 * @param fromFileName file name in which the include was found.
216 * @param toFileName file name that is included.
218 void addInclude(const char *fromFileName,const char *toFileName)
220 //printf("DefineManager::addInclude(%s,%s)\n",fromFileName,toFileName);
221 if (fromFileName==0 || toFileName==0) return;
222 DefinesPerFile *dpf = m_fileMap.find(fromFileName);
225 dpf = new DefinesPerFile;
227 dpf->addInclude(toFileName);
229 /** Returns a Define object given its name or 0 if the Define does
232 Define *isDefined(const char *name) const
234 Define *d = m_contextDefines.find(name);
235 if (d && d->undef) d=0;
236 //printf("isDefined(%s)=%p\n",name,d);
239 /** Returns a reference to the defines found in the current context. */
240 const DefineDict &defineContext() const
242 return m_contextDefines;
245 static DefineManager *theInstance;
247 /** Helper function to collect all define for a given file */
248 void collectDefinesForFile(const char *fileName,DefineDict *dict)
250 if (fileName==0) return;
251 DefinesPerFile *dpf = m_fileMap.find(fileName);
254 QDict<void> includeStack(17);
255 dpf->collectDefines(dict,includeStack);
259 /** Helper function to return the DefinesPerFile object for a given file name. */
260 DefinesPerFile *find(const char *fileName) const
262 if (fileName==0) return 0;
263 return m_fileMap.find(fileName);
266 /** Creates a new DefineManager object */
267 DefineManager() : m_fileMap(1009), m_contextDefines(1009)
269 m_fileMap.setAutoDelete(TRUE);
272 /** Destroys the object */
273 virtual ~DefineManager()
277 QDict<DefinesPerFile> m_fileMap;
278 DefineDict m_contextDefines;
281 /** Singleton instance */
282 DefineManager *DefineManager::theInstance = 0;
284 /** Collects all defines for a file and all files that the file includes.
285 * This function will recursively call itself for each file.
286 * @param dict The dictionary to fill with the defines. A redefine will
287 * replace a previous definition.
288 * @param includeStack The stack of includes, used to stop recursion in
289 * case there is a cyclic include dependency.
291 void DefineManager::DefinesPerFile::collectDefines(
292 DefineDict *dict,QDict<void> &includeStack)
294 //printf("DefinesPerFile::collectDefines #defines=%d\n",m_defines.count());
296 QDictIterator<void> di(m_includedFiles);
297 for (di.toFirst();(di.current());++di)
299 QCString incFile = di.currentKey();
300 DefinesPerFile *dpf = DefineManager::instance().find(incFile);
301 if (dpf && includeStack.find(incFile)==0)
303 //printf(" processing include %s\n",incFile.data());
304 includeStack.insert(incFile,(void*)0x8);
305 dpf->collectDefines(dict,includeStack);
310 QDictIterator<Define> di(m_defines);
312 for (di.toFirst();(def=di.current());++di)
314 Define *d = dict->find(def->name);
315 if (d!=0) // redefine
317 dict->remove(d->name);
319 dict->insert(def->name,def);
320 //printf(" adding define %s\n",def->name.data());
325 /* -----------------------------------------------------------------
330 static int g_yyLineNr = 1;
331 static int g_yyMLines = 1;
332 static int g_yyColNr = 1;
333 static QCString g_yyFileName;
334 static FileDef *g_yyFileDef;
335 static FileDef *g_inputFileDef;
336 static int g_ifcount = 0;
337 static QStrList *g_pathList = 0;
338 static QStack<FileState> g_includeStack;
339 static QDict<int> *g_argDict;
340 static int g_defArgs = -1;
341 static QCString g_defName;
342 static QCString g_defText;
343 static QCString g_defLitText;
344 static QCString g_defArgsStr;
345 static QCString g_defExtraSpacing;
346 static bool g_defVarArgs;
348 static int g_lastCContext;
349 static int g_lastCPPContext;
350 static QArray<int> g_levelGuard;
351 static BufStr *g_inputBuf;
352 static int g_inputBufPos;
353 static BufStr *g_outputBuf;
354 static int g_roundCount;
355 static bool g_quoteArg;
356 static DefineDict *g_expandedDict;
357 static int g_findDefArgContext;
358 static bool g_expectGuard;
359 static QCString g_guardName;
360 static QCString g_lastGuardName;
361 static QCString g_incName;
362 static QCString g_guardExpr;
363 static int g_curlyCount;
364 static bool g_nospaces; // add extra spaces during macro expansion
366 static bool g_macroExpansion; // from the configuration
367 static bool g_expandOnlyPredef; // from the configuration
368 static int g_commentCount;
369 static bool g_insideComment;
370 static bool g_isImported;
371 static QCString g_blockName;
372 static int g_condCtx;
374 static QStack<CondCtx> g_condStack;
375 static bool g_insideCS; // C# has simpler preprocessor
376 static bool g_isSource;
378 static bool g_lexInit = FALSE;
379 static int g_fenceSize = 0;
380 static bool g_ccomment;
382 //DefineDict* getGlobalDefineDict()
384 // return g_globalDefineDict;
387 static void setFileName(const char *name)
391 g_yyFileName=fi.absFilePath().utf8();
392 g_yyFileDef=findFileDef(Doxygen::inputNameDict,g_yyFileName,ambig);
393 if (g_yyFileDef==0) // if this is not an input file check if it is an
396 g_yyFileDef=findFileDef(Doxygen::includeNameDict,g_yyFileName,ambig);
398 //printf("setFileName(%s) g_yyFileName=%s g_yyFileDef=%p\n",
399 // name,g_yyFileName.data(),g_yyFileDef);
400 if (g_yyFileDef && g_yyFileDef->isReference()) g_yyFileDef=0;
401 g_insideCS = getLanguageFromFileName(g_yyFileName)==SrcLangExt_CSharp;
402 g_isSource = guessSection(g_yyFileName);
405 static void incrLevel()
408 g_levelGuard.resize(g_level);
409 g_levelGuard[g_level-1]=FALSE;
410 //printf("%s line %d: incrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level);
413 static void decrLevel()
415 //printf("%s line %d: decrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level);
419 g_levelGuard.resize(g_level);
423 warn(g_yyFileName,g_yyLineNr,"More #endif's than #if's found.\n");
427 static bool otherCaseDone()
431 warn(g_yyFileName,g_yyLineNr,"Found an #else without a preceding #if.\n");
436 return g_levelGuard[g_level-1];
440 static void setCaseDone(bool value)
442 g_levelGuard[g_level-1]=value;
445 static QDict<void> g_allIncludes(10009);
447 static FileState *checkAndOpenFile(const QCString &fileName,bool &alreadyIncluded)
449 alreadyIncluded = FALSE;
451 //printf("checkAndOpenFile(%s)\n",fileName.data());
452 QFileInfo fi(fileName);
453 if (fi.exists() && fi.isFile())
455 static QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
456 if (patternMatch(fi,&exclPatterns)) return 0;
458 QCString absName = fi.absFilePath().utf8();
461 if (g_curlyCount==0) // not #include inside { ... }
463 if (g_allIncludes.find(absName)!=0)
465 alreadyIncluded = TRUE;
466 //printf(" already included 1\n");
467 return 0; // already done
469 g_allIncludes.insert(absName,(void *)0x8);
471 // check include stack for absName
473 QStack<FileState> tmpStack;
474 g_includeStack.setAutoDelete(FALSE);
475 while ((fs=g_includeStack.pop()))
477 if (fs->fileName==absName) alreadyIncluded=TRUE;
480 while ((fs=tmpStack.pop()))
482 g_includeStack.push(fs);
484 g_includeStack.setAutoDelete(TRUE);
488 //printf(" already included 2\n");
491 //printf("#include %s\n",absName.data());
493 fs = new FileState(fi.size()+4096);
494 alreadyIncluded = FALSE;
495 if (!readInputFile(absName,fs->fileBuf))
497 //printf(" error reading\n");
503 fs->oldFileBuf = g_inputBuf;
504 fs->oldFileBufPos = g_inputBufPos;
510 static FileState *findFile(const char *fileName,bool localInclude,bool &alreadyIncluded)
512 //printf("** findFile(%s,%d) g_yyFileName=%s\n",fileName,localInclude,g_yyFileName.data());
513 if (portable_isAbsolutePath(fileName))
515 FileState *fs = checkAndOpenFile(fileName,alreadyIncluded);
518 setFileName(fileName);
522 else if (alreadyIncluded)
527 if (localInclude && !g_yyFileName.isEmpty())
529 QFileInfo fi(g_yyFileName);
532 QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+fileName;
533 FileState *fs = checkAndOpenFile(absName,alreadyIncluded);
536 setFileName(absName);
540 else if (alreadyIncluded)
550 char *s=g_pathList->first();
553 QCString absName = (QCString)s+"/"+fileName;
554 //printf(" Looking for %s in %s\n",fileName,s);
555 FileState *fs = checkAndOpenFile(absName,alreadyIncluded);
558 setFileName(absName);
560 //printf(" -> found it\n");
563 else if (alreadyIncluded)
568 s=g_pathList->next();
573 static QCString extractTrailingComment(const char *s)
585 if (i>=0 && s[i]=='*') // end of a comment block
588 while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--;
593 // only /*!< or /**< are treated as a comment for the macro name,
594 // otherwise the comment is treated as part of the macro definition
595 return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : "";
603 // whitespace or line-continuation
618 static int getNextChar(const QCString &expr,QCString *rest,uint &pos);
619 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos);
620 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c);
621 static void expandExpression(QCString &expr,QCString *rest,int pos);
623 static QCString stringize(const QCString &s)
632 if (!inString && !inChar)
634 while (i<s.length() && !inString && !inChar)
655 while (i<s.length() && inChar)
676 while (i<s.length() && inString)
692 //printf("stringize `%s'->`%s'\n",s.data(),result.data());
696 /*! Execute all ## operators in expr.
697 * If the macro name before or after the operator contains a no-rescan
698 * marker (@-) then this is removed (before the concatenated macro name
699 * may be expanded again.
701 static void processConcatOperators(QCString &expr)
703 //printf("processConcatOperators: in=`%s'\n",expr.data());
704 QRegExp r("[ \\t\\n]*##[ \\t\\n]*");
706 if (expr.isEmpty()) return;
707 while ((n=r.match(expr,i,&l))!=-1)
709 //printf("Match: `%s'\n",expr.data()+i);
710 if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-')
712 // remove no-rescan marker after ID
715 //printf("found `%s'\n",expr.mid(n,l).data());
716 // remove the ## operator and the surrounding whitespace
717 expr=expr.left(n)+expr.right(expr.length()-n-l);
719 while (k>=0 && isId(expr.at(k))) k--;
720 if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@')
722 // remove no-rescan marker before ID
723 expr=expr.left(k-1)+expr.right(expr.length()-k-1);
728 //printf("processConcatOperators: out=`%s'\n",expr.data());
731 static void yyunput (int c,char *buf_ptr );
732 static void returnCharToStream(char c)
737 static inline void addTillEndOfString(const QCString &expr,QCString *rest,
738 uint &pos,char term,QCString &arg)
741 while ((cc=getNextChar(expr,rest,pos))!=EOF && cc!=0)
743 if (cc=='\\') arg+=(char)cc,cc=getNextChar(expr,rest,pos);
744 else if (cc==term) return;
749 /*! replaces the function macro \a def whose argument list starts at
750 * \a pos in expression \a expr.
751 * Notice that this routine may scan beyond the \a expr string if needed.
752 * In that case the characters will be read from the input file.
753 * The replacement string will be returned in \a result and the
754 * length of the (unexpanded) argument list is stored in \a len.
756 static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result)
758 //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);
763 while ((cc=getCurrentChar(expr,rest,j))!=EOF && isspace(cc))
766 getNextChar(expr,rest,j);
770 unputChar(expr,rest,j,' ');
773 getNextChar(expr,rest,j); // eat the `(' character
775 QDict<QCString> argTable; // list of arguments
776 argTable.setAutoDelete(TRUE);
781 // PHASE 1: read the macro arguments
784 while ((cc=getNextChar(expr,rest,j))!=EOF && cc!=0)
792 while (!done && (argCount<def->nargs || def->varArgs) &&
793 ((cc=getNextChar(expr,rest,j))!=EOF && cc!=0)
797 if (c=='(') // argument is a function => search for matching )
802 while ((cc=getNextChar(expr,rest,j))!=EOF && cc!=0)
805 //printf("processing %c: term=%c (%d)\n",c,term,term);
806 if (c=='\'' || c=='\"') // skip ('s and )'s inside strings
809 addTillEndOfString(expr,rest,j,c,arg);
826 else if (c==')' || c==',') // last or next argument found
828 if (c==',' && argCount==def->nargs-1 && def->varArgs)
830 arg=arg.stripWhiteSpace();
836 argKey.sprintf("@%d",argCount++); // key name
837 arg=arg.stripWhiteSpace();
838 // add argument to the lookup table
839 argTable.insert(argKey, new QCString(arg));
841 if (c==')') // end of the argument list
847 else if (c=='\"') // append literal strings
851 while (!found && (cc=getNextChar(expr,rest,j))!=EOF && cc!=0)
858 if ((cc=getNextChar(expr,rest,j))==EOF || cc==0) break;
864 else if (c=='\'') // append literal characters
868 while (!found && (cc=getNextChar(expr,rest,j))!=EOF && cc!=0)
875 if ((cc=getNextChar(expr,rest,j))==EOF || cc==0) break;
881 else // append other characters
888 // PHASE 2: apply the macro function
889 if (argCount==def->nargs ||
890 (argCount>def->nargs && def->varArgs)) // matching parameters lists
893 // substitution of all formal arguments
895 const QCString d=def->definition.stripWhiteSpace();
896 //printf("Macro definition: %s\n",d.data());
900 if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
902 if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
905 resExpr+="@@"; // we unescape these later
907 else if (d.at(k+1)=='-') // no-rescan marker
912 else // argument marker => read the argument number
918 // search for ## backward
919 if (l>=0 && d.at(l)=='"') l--;
920 while (l>=0 && d.at(l)==' ') l--;
921 if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
924 while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
927 // search for ## forward
929 if (l<(int)d.length() && d.at(l)=='"') l++;
930 while (l<(int)d.length() && d.at(l)==' ') l++;
931 if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
933 //printf("request key %s result %s\n",key.data(),argTable[key]->data());
934 if (key.length()>1 && (subst=argTable[key]))
936 QCString substArg=*subst;
937 //printf("substArg=`%s'\n",substArg.data());
938 // only if no ## operator is before or after the argument
939 // marker we do macro expansion.
940 if (!hash) expandExpression(substArg,0,0);
943 //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data());
945 // if the marker is inside a string (because a # was put
946 // before the macro name) we must escape " and \ characters
947 resExpr+=stringize(substArg);
951 if (hash && substArg.isEmpty())
953 resExpr+="@E"; // empty argument will be remove later on
961 resExpr+=" "+substArg+" ";
967 else // no marker, just copy
969 if (!inString && d.at(k)=='\"')
971 inString=TRUE; // entering a literal string
973 else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
975 inString=FALSE; // leaving a literal string
982 //printf("result after substitution `%s' expr=`%s'\n",
983 // result.data(),expr.mid(pos,len).data());
990 /*! returns the next identifier in string \a expr by starting at position \a p.
991 * The position of the identifier is returned (or -1 if nothing is found)
992 * and \a l is its length. Any quoted strings are skipping during the search.
994 static int getNextId(const QCString &expr,int p,int *l)
997 while (p<(int)expr.length())
1000 if (isdigit(c)) // skip number
1002 while (p<(int)expr.length() && isId(expr.at(p))) p++;
1004 else if (isalpha(c) || c=='_') // read id
1007 while (p<(int)expr.length() && isId(expr.at(p))) p++;
1011 else if (c=='"') // skip string
1014 if (p<(int)expr.length()) c=expr.at(p);
1015 while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\')))
1016 // continue as long as no " is found, but ignoring \", but not \\"
1023 if (p<(int)expr.length()) ++p; // skip closing quote
1025 else if (c=='/') // skip C Comment
1027 //printf("Found C comment at p=%d\n",p);
1029 if (p<(int)expr.length())
1032 if (c=='*') // Start of C comment
1035 while (p<(int)expr.length() && !(pc=='*' && c=='/'))
1042 //printf("Found end of C comment at p=%d\n",p);
1048 /*! preforms recursive macro expansion on the string \a expr
1049 * starting at position \a pos.
1050 * May read additional characters from the input while re-scanning!
1051 * If \a expandAll is \c TRUE then all macros in the expression are
1052 * expanded, otherwise only the first is expanded.
1054 static void expandExpression(QCString &expr,QCString *rest,int pos)
1056 //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0);
1059 bool definedTest=FALSE;
1061 while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
1063 bool replaced=FALSE;
1064 macroName=expr.mid(p,l);
1065 //printf("macroName=%s\n",macroName.data());
1066 if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
1068 if (g_expandedDict->find(macroName)==0) // expand macro
1070 Define *def=DefineManager::instance().isDefined(macroName);
1071 if (definedTest) // macro name was found after defined
1073 if (def) expMacro = " 1 "; else expMacro = " 0 ";
1078 else if (def && def->nargs==-1) // simple macro
1080 // substitute the definition of the macro
1081 //printf("macro `%s'->`%s'\n",macroName.data(),def->definition.data());
1084 expMacro=def->definition.stripWhiteSpace();
1088 expMacro=" "+def->definition.stripWhiteSpace()+" ";
1090 //expMacro=def->definition.stripWhiteSpace();
1093 //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data());
1095 else if (def && def->nargs>=0) // function macro
1097 replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro);
1100 else if (macroName=="defined")
1102 //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data());
1106 if (replaced) // expand the macro and rescan the expression
1109 //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data());
1110 QCString resultExpr=expMacro;
1111 QCString restExpr=expr.right(expr.length()-len-p);
1112 processConcatOperators(resultExpr);
1113 if (def && !def->nonRecursive)
1115 g_expandedDict->insert(macroName,def);
1116 expandExpression(resultExpr,&restExpr,0);
1117 g_expandedDict->remove(macroName);
1119 expr=expr.left(p)+resultExpr+restExpr;
1121 //printf("new expression: %s\n",expr.data());
1123 else // move to the next macro name
1125 //printf("moving to the next macro old=%d new=%d\n",i,p+l);
1129 else // move to the next macro name
1131 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
1132 //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data());
1137 else // no re-scan marker found, skip the macro name
1139 //printf("skipping marked macro\n");
1145 /*! replaces all occurrences of @@@@ in \a s by @@
1146 * and removes all occurrences of @@E.
1147 * All identifiers found are replaced by 0L
1149 QCString removeIdsAndMarkers(const char *s)
1151 //printf("removeIdsAndMarkers(%s)\n",s);
1160 if (c=='@') // replace @@ with @ and remove @E
1166 else if (*(p+1)=='E')
1172 else if (isdigit(c)) // number
1178 else if (c=='d' && !inNum) // identifier starting with a `d'
1180 if (qstrncmp(p,"defined ",8)==0 || qstrncmp(p,"defined(",8)==0)
1183 p+=7; // skip defined
1189 while ((c=*p) && isId(c)) p++;
1192 else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
1196 while ((c=*p) && isId(c)) p++;
1197 if (*p=='(') // undefined function macro
1203 if (c=='(') count++;
1207 if (count==0) break;
1213 if (c=='*') // start of C comment
1215 while (*p && !(pc=='*' && c=='/')) // search end of comment
1226 else if (c=='/') // skip C comments
1230 if (c=='*') // start of C comment
1232 while (*p && !(pc=='*' && c=='/')) // search end of comment
1239 else // oops, not comment but division
1250 if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE;
1255 //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data());
1259 /*! replaces all occurrences of @@ in \a s by @
1261 * \a s only contains pairs of @@'s
1263 QCString removeMarkers(const char *s)
1274 case '@': // replace @@ with @
1283 case '/': // skip C comments
1288 if (c=='*') // start of C comment
1290 while (*p && !(pc=='*' && c=='/')) // search end of comment
1292 if (*p=='@' && *(p+1)=='@')
1299 if (*p) result+=c,p++;
1303 case '"': // skip string literals
1308 while (*p && (c!='"' || pc=='\\')) // no end quote
1313 if (*p) result+=c,p++;
1316 case '\'': // skip char literals
1321 while (*p && (c!='\'' || pc=='\\')) // no end quote
1326 if (*p) result+=c,p++;
1338 //printf("RemoveMarkers(%s)=%s\n",s,result.data());
1342 /*! compute the value of the expression in string \a expr.
1343 * If needed the function may read additional characters from the input.
1346 bool computeExpression(const QCString &expr)
1349 expandExpression(e,0,0);
1350 //printf("after expansion `%s'\n",e.data());
1351 e = removeIdsAndMarkers(e);
1352 if (e.isEmpty()) return FALSE;
1353 //printf("parsing `%s'\n",e.data());
1354 return parseconstexp(g_yyFileName,g_yyLineNr,e);
1357 /*! expands the macro definition in \a name
1358 * If needed the function may read additional characters from the input
1361 QCString expandMacro(const QCString &name)
1364 expandExpression(n,0,0);
1366 //printf("expandMacro `%s'->`%s'\n",name.data(),n.data());
1372 Define *def=new Define;
1373 def->name = g_defName;
1374 def->definition = g_defText.stripWhiteSpace();
1375 def->nargs = g_defArgs;
1376 def->fileName = g_yyFileName;
1377 def->fileDef = g_yyFileDef;
1378 def->lineNr = g_yyLineNr-g_yyMLines;
1379 def->columnNr = g_yyColNr;
1380 def->varArgs = g_defVarArgs;
1381 //printf("newDefine: %s %s file: %s\n",def->name.data(),def->definition.data(),
1382 // def->fileDef ? def->fileDef->name().data() : def->fileName.data());
1383 //printf("newDefine: `%s'->`%s'\n",def->name.data(),def->definition.data());
1384 if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name])
1386 def->isPredefined=TRUE;
1393 if (g_skip) return; // do not add this define as it is inside a
1394 // conditional section (cond command) that is disabled.
1395 if (!Doxygen::gatherDefines) return;
1397 //printf("addDefine %s %s\n",g_defName.data(),g_defArgsStr.data());
1398 //ArgumentList *al = new ArgumentList;
1399 //stringToArgumentList(g_defArgsStr,al);
1400 MemberDef *md=new MemberDef(
1401 g_yyFileName,g_yyLineNr-g_yyMLines,g_yyColNr,
1402 "#define",g_defName,g_defArgsStr,0,
1403 Public,Normal,FALSE,Member,MemberType_Define,0,0);
1404 if (!g_defArgsStr.isEmpty())
1406 ArgumentList *argList = new ArgumentList;
1407 //printf("addDefine() g_defName=`%s' g_defArgsStr=`%s'\n",g_defName.data(),g_defArgsStr.data());
1408 stringToArgumentList(g_defArgsStr,argList);
1409 md->setArgumentList(argList);
1411 //printf("Setting initializer for `%s' to `%s'\n",g_defName.data(),g_defText.data());
1412 int l=g_defLitText.find('\n');
1413 if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\")
1415 // strip first line if it only contains a slash
1416 g_defLitText = g_defLitText.right(g_defLitText.length()-l-1);
1420 // align the items on the first line with the items on the second line
1422 const char *p=g_defLitText.data()+k;
1424 while ((c=*p++) && (c==' ' || c=='\t')) k++;
1425 g_defLitText=g_defLitText.mid(l+1,k-l-1)+g_defLitText.stripWhiteSpace();
1427 md->setInitializer(g_defLitText.stripWhiteSpace());
1429 //printf("pre.l: md->setFileDef(%p)\n",g_inputFileDef);
1430 md->setFileDef(g_inputFileDef);
1431 md->setDefinition("#define "+g_defName);
1433 MemberName *mn=Doxygen::functionNameSDict->find(g_defName);
1436 mn = new MemberName(g_defName);
1437 Doxygen::functionNameSDict->append(g_defName,mn);
1442 g_yyFileDef->insertMember(md);
1446 //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine());
1449 static inline void outputChar(char c)
1451 if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addChar(c);
1454 static inline void outputArray(const char *a,int len)
1456 if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addArray(a,len);
1459 static void readIncludeFile(const QCString &inc)
1461 static bool searchIncludes = Config_getBool("SEARCH_INCLUDES");
1464 // find the start of the include file name
1465 while (i<inc.length() &&
1466 (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
1470 // was it a local include?
1471 bool localInclude = s>0 && inc.at(s-1)=='"';
1473 // find the end of the include file name
1474 while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
1476 if (s<inc.length() && i>s) // valid include file name found
1478 // extract include path+name
1479 QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
1481 QCString dosExt = incFileName.right(4);
1482 if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb")
1484 // skip imported binary files (e.g. M$ type libraries)
1488 QCString oldFileName = g_yyFileName;
1489 FileDef *oldFileDef = g_yyFileDef;
1490 int oldLineNr = g_yyLineNr;
1491 //printf("Searching for `%s'\n",incFileName.data());
1493 // absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336)
1494 QCString absIncFileName = incFileName;
1496 QFileInfo fi(g_yyFileName);
1499 QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName;
1500 QFileInfo fi2(absName);
1503 absIncFileName=fi2.absFilePath().utf8();
1505 else if (searchIncludes) // search in INCLUDE_PATH as well
1507 QStrList &includePath = Config_getList("INCLUDE_PATH");
1508 char *s=includePath.first();
1512 if (fi.exists() && fi.isDir())
1514 QCString absName = QCString(fi.absFilePath().utf8())+"/"+incFileName;
1515 //printf("trying absName=%s\n",absName.data());
1516 QFileInfo fi2(absName);
1519 absIncFileName=fi2.absFilePath().utf8();
1522 //printf( "absIncFileName = %s\n", absIncFileName.data() );
1524 s=includePath.next();
1527 //printf( "absIncFileName = %s\n", absIncFileName.data() );
1530 DefineManager::instance().addInclude(g_yyFileName,absIncFileName);
1531 DefineManager::instance().addFileToContext(absIncFileName);
1533 // findFile will overwrite g_yyFileDef if found
1535 bool alreadyIncluded = FALSE;
1536 //printf("calling findFile(%s)\n",incFileName.data());
1537 if ((fs=findFile(incFileName,localInclude,alreadyIncluded))) // see if the include file can be found
1539 //printf("Found include file!\n");
1540 if (Debug::isFlagSet(Debug::Preprocessor))
1542 for (i=0;i<g_includeStack.count();i++)
1544 Debug::print(Debug::Preprocessor,0," ");
1546 //msg("#include %s: parsing...\n",incFileName.data());
1550 // add include dependency to the file in which the #include was found
1552 // change to absolute name for bug 641336
1553 FileDef *incFd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1554 oldFileDef->addIncludeDependency(ambig ? 0 : incFd,incFileName,localInclude,g_isImported,FALSE);
1555 // add included by dependency
1558 //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data());
1559 g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1562 else if (g_inputFileDef)
1564 g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1566 fs->bufState = YY_CURRENT_BUFFER;
1567 fs->lineNr = oldLineNr;
1568 fs->fileName = oldFileName;
1569 // push the state on the stack
1570 g_includeStack.push(fs);
1571 // set the scanner to the include file
1573 // Deal with file changes due to
1574 // #include's within { .. } blocks
1575 QCString lineStr(g_yyFileName.length()+20);
1576 lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data());
1577 outputArray(lineStr.data(),lineStr.length());
1579 DBG_CTX((stderr,"Switching to include file %s\n",incFileName.data()));
1581 g_inputBuf = &fs->fileBuf;
1583 yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE));
1587 //printf(" calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded);
1591 //QCString absPath = incFileName;
1592 //if (QDir::isRelativePath(incFileName))
1594 // absPath = QDir::cleanDirPath(oldFileDef->getPath()+"/"+incFileName);
1595 // //printf("%s + %s -> resolved path %s\n",oldFileDef->getPath().data(),incFileName.data(),absPath.data());
1598 // change to absolute name for bug 641336
1599 FileDef *fd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1600 //printf("%s::findFileDef(%s)=%p\n",oldFileDef->name().data(),incFileName.data(),fd);
1601 // add include dependency to the file in which the #include was found
1602 oldFileDef->addIncludeDependency(ambig ? 0 : fd,incFileName,localInclude,g_isImported,FALSE);
1603 // add included by dependency
1606 //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig);
1607 fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1610 else if (g_inputFileDef)
1612 g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1614 if (Debug::isFlagSet(Debug::Preprocessor))
1616 if (alreadyIncluded)
1618 Debug::print(Debug::Preprocessor,0,"#include %s: already included! skipping...\n",incFileName.data());
1622 Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",incFileName.data());
1624 //printf("error: include file %s not found\n",yytext);
1626 if (g_curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... }
1628 warn(g_yyFileName,g_yyLineNr,"include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data());
1634 /* ----------------------------------------------------------------- */
1636 static void startCondSection(const char *sectId)
1638 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1640 bool expResult = prs.parse(g_yyFileName,g_yyLineNr,sectId);
1641 g_condStack.push(new CondCtx(g_yyLineNr,sectId,g_skip));
1646 //printf(" expResult=%d skip=%d\n",expResult,g_skip);
1649 static void endCondSection()
1651 if (g_condStack.isEmpty())
1657 CondCtx *ctx = g_condStack.pop();
1660 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1663 static void forceEndCondSection()
1665 while (!g_condStack.isEmpty())
1672 static QCString escapeAt(const char *text)
1681 if (c=='@') result+="@@"; else result+=c;
1687 static char resolveTrigraph(char c)
1691 case '=': return '#';
1692 case '/': return '\\';
1693 case '\'': return '^';
1694 case '(': return '[';
1695 case ')': return ']';
1696 case '!': return '|';
1697 case '<': return '{';
1698 case '>': return '}';
1699 case '-': return '~';
1704 /* ----------------------------------------------------------------- */
1707 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
1709 static int yyread(char *buf,int max_size)
1711 int bytesInBuf = g_inputBuf->curPos()-g_inputBufPos;
1712 int bytesToCopy = QMIN(max_size,bytesInBuf);
1713 memcpy(buf,g_inputBuf->data()+g_inputBufPos,bytesToCopy);
1714 g_inputBufPos+=bytesToCopy;
1718 /* ----------------------------------------------------------------- */
1722 ID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
1725 CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
1770 <*>"??"[=/'()!<>-] { // Trigraph
1771 unput(resolveTrigraph(yytext[2]));
1773 <Start>^{B}*"#" { BEGIN(Command); g_yyColNr+=yyleng; g_yyMLines=0;}
1775 outputArray(yytext,(int)yyleng);
1778 <Start>^{B}*[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]+{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors?
1780 for (i=(int)yyleng-1;i>=0;i--)
1786 <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
1787 <Start>^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\)\n]*")"{B}*\n { // function like macro
1788 static bool skipFuncMacros = Config_getBool("SKIP_FUNCTION_MACROS");
1789 QCString name(yytext);
1790 name=name.left(name.find('(')).stripWhiteSpace();
1793 if (skipFuncMacros &&
1794 name!="Q_PROPERTY" &&
1796 (g_includeStack.isEmpty() || g_curlyCount>0) &&
1798 (def=DefineManager::instance().isDefined(name)) &&
1799 /*macroIsAccessible(def) &&*/
1800 (!g_expandOnlyPredef || def->isPredefined)
1810 for (i=(int)yyleng-1;i>=0;i--)
1817 <CopyLine>"extern"{BN}{0,80}"\"C\""*{BN}{0,80}"{" {
1818 QCString text=yytext;
1819 g_yyLineNr+=text.contains('\n');
1820 outputArray(yytext,(int)yyleng);
1822 <CopyLine>"{" { // count brackets inside the main file
1823 if (g_includeStack.isEmpty())
1827 outputChar(*yytext);
1829 <CopyLine>"}" { // count brackets inside the main file
1830 if (g_includeStack.isEmpty() && g_curlyCount>0)
1834 outputChar(*yytext);
1836 <CopyLine>"'"\\[0-7]{1,3}"'" {
1837 outputArray(yytext,(int)yyleng);
1839 <CopyLine>"'"\\."'" {
1840 outputArray(yytext,(int)yyleng);
1843 outputArray(yytext,(int)yyleng);
1846 outputChar(*yytext);
1847 BEGIN( CopyString );
1849 <CopyString>[^\"\\\r\n]+ {
1850 outputArray(yytext,(int)yyleng);
1853 outputArray(yytext,(int)yyleng);
1856 outputChar(*yytext);
1859 <CopyLine>{ID}/{BN}{0,80}"(" {
1860 g_expectGuard = FALSE;
1862 //def=g_globalDefineDict->find(yytext);
1863 //def=DefineManager::instance().isDefined(yytext);
1864 //printf("Search for define %s found=%d g_includeStack.isEmpty()=%d "
1865 // "g_curlyCount=%d g_macroExpansion=%d g_expandOnlyPredef=%d "
1866 // "isPreDefined=%d\n",yytext,def ? 1 : 0,
1867 // g_includeStack.isEmpty(),g_curlyCount,g_macroExpansion,g_expandOnlyPredef,
1868 // def ? def->isPredefined : -1
1870 if ((g_includeStack.isEmpty() || g_curlyCount>0) &&
1872 (def=DefineManager::instance().isDefined(yytext)) &&
1873 /*(def->isPredefined || macroIsAccessible(def)) && */
1874 (!g_expandOnlyPredef || def->isPredefined)
1877 //printf("Found it! #args=%d\n",def->nargs);
1879 g_defArgsStr=yytext;
1880 if (def->nargs==-1) // no function macro
1882 QCString result = def->isPredefined ? def->definition : expandMacro(g_defArgsStr);
1883 outputArray(result,result.length());
1885 else // zero or more arguments
1887 g_findDefArgContext = CopyLine;
1888 BEGIN(FindDefineArgs);
1893 outputArray(yytext,(int)yyleng);
1898 if ((g_includeStack.isEmpty() || g_curlyCount>0) &&
1900 (def=DefineManager::instance().isDefined(yytext)) &&
1902 /*(def->isPredefined || macroIsAccessible(def)) &&*/
1903 (!g_expandOnlyPredef || def->isPredefined)
1906 QCString result=def->isPredefined ? def->definition : expandMacro(yytext);
1907 outputArray(result,result.length());
1911 outputArray(yytext,(int)yyleng);
1914 <CopyLine>"\\"\r?/\n { // strip line continuation characters
1917 outputChar(*yytext);
1925 <FindDefineArgs>"(" {
1929 <FindDefineArgs>")" {
1932 if (g_roundCount==0)
1934 QCString result=expandMacro(g_defArgsStr);
1935 //printf("g_defArgsStr=`%s'->`%s'\n",g_defArgsStr.data(),result.data());
1936 if (g_findDefArgContext==CopyLine)
1938 outputArray(result,result.length());
1939 BEGIN(g_findDefArgContext);
1941 else // g_findDefArgContext==IncludeID
1943 readIncludeFile(result);
1950 <FindDefineArgs>")"{B}*"(" {
1951 g_defArgsStr+=yytext;
1954 <FindDefineArgs>{CHARLIT} {
1955 g_defArgsStr+=yytext;
1957 <FindDefineArgs>"/*"[*]? {
1958 g_defArgsStr+=yytext;
1959 BEGIN(ArgCopyCComment);
1961 <FindDefineArgs>\" {
1962 g_defArgsStr+=*yytext;
1965 <FindDefineArgs>\n {
1970 <FindDefineArgs>"@" {
1974 g_defArgsStr+=*yytext;
1976 <ArgCopyCComment>[^*\n]+ {
1977 g_defArgsStr+=yytext;
1979 <ArgCopyCComment>"*/" {
1980 g_defArgsStr+=yytext;
1981 BEGIN(FindDefineArgs);
1983 <ArgCopyCComment>\n {
1988 <ArgCopyCComment>. {
1989 g_defArgsStr+=yytext;
1992 g_defArgsStr+=*yytext;
1993 BEGIN(FindDefineArgs);
1995 <ReadString>"//"|"/*" {
1996 g_defArgsStr+=yytext;
1999 g_defArgsStr+=yytext;
2002 g_defArgsStr+=*yytext;
2004 <Command>("include"|"import"){B}+/{ID} {
2005 g_isImported = yytext[1]=='m';
2006 if (g_macroExpansion)
2009 <Command>("include"|"import"){B}*[<"] {
2010 g_isImported = yytext[1]=='m';
2012 c[0]=yytext[yyleng-1];c[1]='\0';
2016 <Command>("cmake")?"define"{B}+ {
2017 //printf("!!!DefName\n");
2021 <Command>"ifdef"/{B}*"(" {
2023 g_guardExpr.resize(0);
2024 BEGIN(DefinedExpr2);
2026 <Command>"ifdef"/{B}+ {
2027 //printf("Pre.l: ifdef\n");
2029 g_guardExpr.resize(0);
2030 BEGIN(DefinedExpr1);
2032 <Command>"ifndef"/{B}*"(" {
2035 BEGIN(DefinedExpr2);
2037 <Command>"ifndef"/{B}+ {
2040 BEGIN(DefinedExpr1);
2042 <Command>"if"/[ \t(!] {
2044 g_guardExpr.resize(0);
2047 <Command>("elif"|"else"{B}*"if")/[ \t(!] {
2048 if (!otherCaseDone())
2050 g_guardExpr.resize(0);
2056 BEGIN(SkipCPPBlock);
2059 <Command>"else"/[^a-z_A-Z0-9\x80-\xFF] {
2060 //printf("else g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2061 if (otherCaseDone())
2064 BEGIN(SkipCPPBlock);
2069 //g_levelGuard[g_level-1]=TRUE;
2072 <Command>"undef"{B}+ {
2075 <Command>("elif"|"else"{B}*"if")/[ \t(!] {
2076 if (!otherCaseDone())
2078 g_guardExpr.resize(0);
2082 <Command>"endif"/[^a-z_A-Z0-9\x80-\xFF] {
2083 //printf("Pre.l: #endif\n");
2086 <Command,IgnoreLine>\n {
2091 <Command>"pragma"{B}+"once" {
2092 g_expectGuard = FALSE;
2094 <Command>{ID} { // unknown directive
2097 <IgnoreLine>\\[\r]?\n {
2102 <Command>. {g_yyColNr+=yyleng;}
2105 if ((def=DefineManager::instance().isDefined(yytext))
2106 /*&& !def->isPredefined*/
2107 && !def->nonRecursive
2110 //printf("undefining %s\n",yytext);
2120 <Guard>"defined"/{B}*"(" {
2121 BEGIN(DefinedExpr2);
2123 <Guard>"defined"/{B}+ {
2124 BEGIN(DefinedExpr1);
2126 <Guard>{ID} { g_guardExpr+=yytext; }
2127 <Guard>. { g_guardExpr+=*yytext; }
2130 //printf("Guard: `%s'\n",
2131 // g_guardExpr.data());
2132 bool guard=computeExpression(g_guardExpr);
2134 //printf("if g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2142 BEGIN(SkipCPPBlock);
2145 <DefinedExpr1,DefinedExpr2>\\\n { g_yyLineNr++; outputChar('\n'); }
2146 <DefinedExpr1>{ID} {
2147 if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2148 g_guardExpr+=" 1L ";
2150 g_guardExpr+=" 0L ";
2151 g_lastGuardName=yytext;
2154 <DefinedExpr2>{ID} {
2155 if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2156 g_guardExpr+=" 1L ";
2158 g_guardExpr+=" 0L ";
2159 g_lastGuardName=yytext;
2161 <DefinedExpr1,DefinedExpr2>\n { // should not happen, handle anyway
2164 BEGIN(SkipCPPBlock);
2169 <DefinedExpr1,DefinedExpr2>.
2170 <SkipCPPBlock>^{B}*"#" { BEGIN(SkipCommand); }
2171 <SkipCPPBlock>^{B}*/[^#] { BEGIN(SkipLine); }
2172 <SkipCPPBlock>\n { g_yyLineNr++; outputChar('\n'); }
2174 <SkipCommand>"if"(("n")?("def"))?/[ \t(!] {
2177 //printf("#if... depth=%d\n",g_ifcount);
2179 <SkipCommand>"else" {
2180 //printf("Else! g_ifcount=%d otherCaseDone=%d\n",g_ifcount,otherCaseDone());
2181 if (g_ifcount==0 && !otherCaseDone())
2188 <SkipCommand>("elif"|"else"{B}*"if")/[ \t(!] {
2191 if (!otherCaseDone())
2193 g_guardExpr.resize(0);
2194 g_lastGuardName.resize(0);
2199 BEGIN(SkipCPPBlock);
2203 <SkipCommand>"endif" {
2204 g_expectGuard = FALSE;
2215 BEGIN(SkipCPPBlock);
2217 <SkipCommand>{ID} { // unknown directive
2222 <SkipLine>{CHARLIT} { }
2227 <SkipString>"//"/[^\n]* {
2229 <SkipLine,SkipCommand,SkipCPPBlock>"//"[^\n]* {
2230 g_lastCPPContext=YY_START;
2231 BEGIN(RemoveCPPComment);
2233 <SkipString>"/*"/[^\n]* {
2235 <SkipLine,SkipCommand,SkipCPPBlock>"/*"/[^\n]* {
2236 g_lastCContext=YY_START;
2237 BEGIN(RemoveCComment);
2242 BEGIN(SkipCPPBlock);
2244 <SkipString>[^"\\\n]+ { }
2250 <IncludeID>{ID}{B}*/"(" {
2253 g_defArgsStr=yytext;
2254 g_findDefArgContext = IncludeID;
2255 BEGIN(FindDefineArgs);
2259 readIncludeFile(expandMacro(yytext));
2262 <Include>[^\">\n]+[\">] {
2264 readIncludeFile(g_incName);
2274 <EndImport>[^\\\n]*/\n {
2277 <EndImport>\\[\r]?"\n" {
2283 <DefName>{ID}/("\\\n")*"(" { // define with argument
2284 //printf("Define() `%s'\n",yytext);
2285 g_argDict = new QDict<int>(31);
2286 g_argDict->setAutoDelete(TRUE);
2288 g_defArgsStr.resize(0);
2289 g_defText.resize(0);
2290 g_defLitText.resize(0);
2292 g_defVarArgs = FALSE;
2293 g_defExtraSpacing.resize(0);
2296 <DefName>{ID}{B}+"1"/[ \r\t\n] { // special case: define with 1 -> can be "guard"
2297 //printf("Define `%s'\n",yytext);
2300 g_defArgsStr.resize(0);
2302 g_defName = g_defName.left(g_defName.length()-1).stripWhiteSpace();
2303 g_defVarArgs = FALSE;
2304 //printf("Guard check: %s!=%s || %d\n",
2305 // g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2306 if (g_curlyCount>0 || g_defName!=g_lastGuardName || !g_expectGuard)
2307 { // define may appear in the output
2308 QCString tmp=(QCString)"#define "+g_defName;
2309 outputArray(tmp.data(),tmp.length());
2311 g_insideComment=FALSE;
2312 g_lastGuardName.resize(0);
2317 else // define is a guard => hide
2319 //printf("Found a guard %s\n",yytext);
2320 g_defText.resize(0);
2321 g_defLitText.resize(0);
2324 g_expectGuard=FALSE;
2326 <DefName>{ID}/{B}*"\n" { // empty define
2330 g_defArgsStr.resize(0);
2331 g_defText.resize(0);
2332 g_defLitText.resize(0);
2333 g_defVarArgs = FALSE;
2334 //printf("Guard check: %s!=%s || %d\n",
2335 // g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2336 if (g_curlyCount>0 || g_defName!=g_lastGuardName || !g_expectGuard)
2337 { // define may appear in the output
2338 QCString tmp=(QCString)"#define "+g_defName;
2339 outputArray(tmp.data(),tmp.length());
2341 g_insideComment=FALSE;
2342 if (g_insideCS) g_defText="1"; // for C#, use "1" as define text
2345 else // define is a guard => hide
2347 //printf("Found a guard %s\n",yytext);
2348 g_guardName = yytext;
2349 g_lastGuardName.resize(0);
2352 g_expectGuard=FALSE;
2354 <DefName>{ID}/{B}* { // define with content
2355 //printf("Define `%s'\n",yytext);
2358 g_defArgsStr.resize(0);
2359 g_defText.resize(0);
2360 g_defLitText.resize(0);
2362 g_defVarArgs = FALSE;
2363 QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr;
2364 outputArray(tmp.data(),tmp.length());
2366 g_insideComment=FALSE;
2370 g_defExtraSpacing+="\n";
2373 <DefineArg>","{B}* { g_defArgsStr+=yytext; }
2374 <DefineArg>"("{B}* { g_defArgsStr+=yytext; }
2375 <DefineArg>{B}*")"{B}* {
2376 g_defArgsStr+=yytext;
2377 QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr+g_defExtraSpacing;
2378 outputArray(tmp.data(),tmp.length());
2380 g_insideComment=FALSE;
2383 <DefineArg>"..." { // Variadic macro
2384 g_defVarArgs = TRUE;
2385 g_defArgsStr+=yytext;
2386 g_argDict->insert("__VA_ARGS__",new int(g_defArgs));
2389 <DefineArg>{ID}{B}*("..."?) {
2390 //printf("Define addArg(%s)\n",yytext);
2391 QCString argName=yytext;
2392 g_defVarArgs = yytext[yyleng-1]=='.';
2393 if (g_defVarArgs) // strip ellipsis
2395 argName=argName.left(argName.length()-3);
2397 argName = argName.stripWhiteSpace();
2398 g_defArgsStr+=yytext;
2399 g_argDict->insert(argName,new int(g_defArgs));
2403 <DefineText>"/ **"|"/ *!" {
2405 g_defLitText+=yytext;
2406 g_insideComment=TRUE;
2410 g_defLitText+=yytext;
2411 g_insideComment=FALSE;
2414 <DefineText>"/*"[!*]? {
2416 g_defLitText+=yytext;
2417 g_lastCContext=YY_START;
2419 BEGIN(CopyCComment);
2421 <DefineText>"//"[!/]? {
2422 outputArray(yytext,(int)yyleng);
2423 g_lastCPPContext=YY_START;
2425 BEGIN(SkipCPPComment);
2427 <SkipCComment>[/]?"*/" {
2428 if (yytext[0]=='/') outputChar('/');
2429 outputChar('*');outputChar('/');
2430 if (--g_commentCount<=0)
2432 if (g_lastCContext==Start)
2433 // small hack to make sure that ^... rule will
2434 // match when going to Start... Example: "/*...*/ some stuff..."
2436 YY_CURRENT_BUFFER->yy_at_bol=1;
2438 BEGIN(g_lastCContext);
2441 <SkipCComment>"//"("/")* {
2442 outputArray(yytext,(int)yyleng);
2444 <SkipCComment>"/*" {
2445 outputChar('/');outputChar('*');
2448 <SkipCComment>[\\@][\\@]("f{"|"f$"|"f[") {
2449 outputArray(yytext,(int)yyleng);
2451 <SkipCComment>"~~~"[~]* {
2452 static bool markdownSupport = Config_getBool("MARKDOWN_SUPPORT");
2453 if (!markdownSupport)
2459 outputArray(yytext,(int)yyleng);
2461 BEGIN(SkipVerbatim);
2464 <SkipCComment>[\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ {
2465 outputArray(yytext,(int)yyleng);
2466 g_yyLineNr+=QCString(yytext).contains('\n');
2468 <SkipCComment>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ {
2469 outputArray(yytext,(int)yyleng);
2470 g_yyLineNr+=QCString(yytext).contains('\n');
2478 QCString bn=&yytext[1];
2479 int i = bn.find('{'); // for \code{.c}
2480 if (i!=-1) bn=bn.left(i);
2481 g_blockName=bn.stripWhiteSpace();
2483 BEGIN(SkipVerbatim);
2485 <SkipCComment,SkipCPPComment>[\\@][\\@]"cond"[ \t]+ { // escaped @cond
2486 outputArray(yytext,(int)yyleng);
2488 <SkipCPPComment>[\\@]"cond"[ \t]+ { // conditional section
2493 <SkipCComment>[\\@]"cond"[ \t]+ { // conditional section
2498 <CondLineC,CondLineCpp>[!()&| \ta-z_A-Z0-9\x80-\xFF.\-]+ {
2499 startCondSection(yytext);
2502 if (YY_START==CondLineC)
2505 outputArray("*/",2);
2519 <CondLineC,CondLineCpp>. { // non-guard character
2521 startCondSection(" ");
2524 if (YY_START==CondLineC)
2527 outputArray("*/",2);
2541 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t\r]*/\n { // no guard
2542 if (YY_START==SkipCComment)
2546 outputArray("*/",2);
2553 startCondSection(" ");
2556 <SkipCond>\n { g_yyLineNr++; outputChar('\n'); }
2558 <SkipCond>[^\/\!*\\@\n]+ { }
2559 <SkipCond>"//"[/!] { g_ccomment=FALSE; }
2560 <SkipCond>"/*"[*!] { g_ccomment=TRUE; }
2561 <SkipCond,SkipCComment,SkipCPPComment>[\\@][\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2564 outputArray(yytext,(int)yyleng);
2567 <SkipCond>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2568 bool oldSkip = g_skip;
2570 if (oldSkip && !g_skip)
2574 outputArray("/** ",4);
2579 <SkipCComment,SkipCPPComment>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2580 bool oldSkip = g_skip;
2582 if (oldSkip && !g_skip)
2587 <SkipVerbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}") { /* end of verbatim block */
2588 outputArray(yytext,(int)yyleng);
2589 if (yytext[1]=='f' && g_blockName=="f")
2591 BEGIN(SkipCComment);
2593 else if (&yytext[4]==g_blockName)
2595 BEGIN(SkipCComment);
2598 <SkipVerbatim>"~~~"[~]* {
2599 outputArray(yytext,(int)yyleng);
2600 if (g_fenceSize==yyleng)
2602 BEGIN(SkipCComment);
2605 <SkipVerbatim>"*/"|"/*" {
2606 outputArray(yytext,(int)yyleng);
2608 <SkipCComment,SkipVerbatim>[^*\\@\x06~\n\/]+ {
2609 outputArray(yytext,(int)yyleng);
2611 <SkipCComment,SkipVerbatim>\n {
2615 <SkipCComment,SkipVerbatim>. {
2616 outputChar(*yytext);
2618 <CopyCComment>[^*a-z_A-Z\x80-\xFF\n]+ {
2619 g_defLitText+=yytext;
2620 g_defText+=escapeAt(yytext);
2622 <CopyCComment>"*/" {
2623 g_defLitText+=yytext;
2625 BEGIN(g_lastCContext);
2630 g_defLitText+=yytext;
2633 <RemoveCComment>"*/"{B}*"#" { // see bug 594021 for a usecase for this rule
2634 if (g_lastCContext==SkipCPPBlock)
2643 <RemoveCComment>"*/" { BEGIN(g_lastCContext); }
2644 <RemoveCComment>"//"
2645 <RemoveCComment>"/*"
2646 <RemoveCComment>[^*\x06\n]+
2647 <RemoveCComment>\n { g_yyLineNr++; outputChar('\n'); }
2649 <SkipCPPComment>[^\n\/\\@]+ {
2650 outputArray(yytext,(int)yyleng);
2652 <SkipCPPComment,RemoveCPPComment>\n {
2654 BEGIN(g_lastCPPContext);
2656 <SkipCPPComment>"/*" {
2657 outputChar('/');outputChar('*');
2659 <SkipCPPComment>"//" {
2660 outputChar('/');outputChar('/');
2662 <SkipCPPComment>[^\x06\@\\\n]+ {
2663 outputArray(yytext,(int)yyleng);
2666 outputChar(*yytext);
2668 <RemoveCPPComment>"/*"
2669 <RemoveCPPComment>"//"
2670 <RemoveCPPComment>[^\x06\n]+
2674 g_defLitText+=yytext;
2676 <DefineText,CopyCComment>{ID} {
2677 g_defLitText+=yytext;
2685 if ((n=(*g_argDict)[yytext]))
2687 //if (!g_quoteArg) g_defText+=' ';
2690 numStr.sprintf("%d",*n);
2692 //if (!g_quoteArg) g_defText+=' ';
2710 g_defLitText+=yytext;
2713 <DefineText>\\[\r]?\n {
2714 g_defLitText+=yytext;
2721 QCString comment=extractTrailingComment(g_defLitText);
2722 g_defLitText+=yytext;
2723 if (!comment.isEmpty())
2725 outputArray(comment,comment.length());
2726 g_defLitText=g_defLitText.left(g_defLitText.length()-comment.length()-1);
2730 //printf("Define name=`%s' text=`%s' litTexti=`%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data());
2731 if (g_includeStack.isEmpty() || g_curlyCount>0)
2735 def=DefineManager::instance().isDefined(g_defName);
2736 if (def==0) // new define
2738 //printf("new define '%s'!\n",g_defName.data());
2739 Define *nd = newDefine();
2740 DefineManager::instance().addDefine(g_yyFileName,nd);
2742 // also add it to the local file list if it is a source file
2743 //if (g_isSource && g_includeStack.isEmpty())
2745 // g_fileDefineDict->insert(g_defName,nd);
2748 else if (def /*&& macroIsAccessible(def)*/)
2749 // name already exists
2751 //printf("existing define!\n");
2752 //printf("define found\n");
2753 if (def->undef) // undefined name
2756 def->name = g_defName;
2757 def->definition = g_defText.stripWhiteSpace();
2758 def->nargs = g_defArgs;
2759 def->fileName = g_yyFileName.copy();
2760 def->lineNr = g_yyLineNr-g_yyMLines;
2761 def->columnNr = g_yyColNr;
2765 //printf("error: define %s is defined more than once!\n",g_defName.data());
2768 delete g_argDict; g_argDict=0;
2771 g_lastGuardName.resize(0);
2774 <DefineText>{B}* { g_defText += ' '; g_defLitText+=yytext; }
2775 <DefineText>{B}*"##"{B}* { g_defText += "##"; g_defLitText+=yytext; }
2776 <DefineText>"@" { g_defText += "@@"; g_defLitText+=yytext; }
2778 g_defText += *yytext;
2779 g_defLitText+=yytext;
2780 if (!g_insideComment)
2782 BEGIN(SkipDoubleQuote);
2785 <DefineText>\' { g_defText += *yytext;
2786 g_defLitText+=yytext;
2787 if (!g_insideComment)
2789 BEGIN(SkipSingleQuote);
2792 <SkipDoubleQuote>"//"[/]? { g_defText += yytext; g_defLitText+=yytext; }
2793 <SkipDoubleQuote>"/*" { g_defText += yytext; g_defLitText+=yytext; }
2794 <SkipDoubleQuote>\" {
2795 g_defText += *yytext; g_defLitText+=yytext;
2798 <SkipSingleQuote,SkipDoubleQuote>\\. {
2799 g_defText += yytext; g_defLitText+=yytext;
2801 <SkipSingleQuote>\' {
2802 g_defText += *yytext; g_defLitText+=yytext;
2805 <SkipDoubleQuote>. { g_defText += *yytext; g_defLitText+=yytext; }
2806 <SkipSingleQuote>. { g_defText += *yytext; g_defLitText+=yytext; }
2807 <DefineText>. { g_defText += *yytext; g_defLitText+=yytext; }
2809 DBG_CTX((stderr,"End of include file\n"));
2810 //printf("Include stack depth=%d\n",g_includeStack.count());
2811 if (g_includeStack.isEmpty())
2813 DBG_CTX((stderr,"Terminating scanner!\n"));
2818 FileState *fs=g_includeStack.pop();
2819 //fileDefineCache->merge(g_yyFileName,fs->fileName);
2820 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
2821 yy_switch_to_buffer( fs->bufState );
2822 yy_delete_buffer( oldBuf );
2823 g_yyLineNr = fs->lineNr;
2824 //preYYin = fs->oldYYin;
2825 g_inputBuf = fs->oldFileBuf;
2826 g_inputBufPos = fs->oldFileBufPos;
2827 setFileName(fs->fileName);
2828 DBG_CTX((stderr,"######## FileName %s\n",g_yyFileName.data()));
2830 // Deal with file changes due to
2831 // #include's within { .. } blocks
2832 QCString lineStr(15+g_yyFileName.length());
2833 lineStr.sprintf("# %d \"%s\" 2",g_yyLineNr,g_yyFileName.data());
2834 outputArray(lineStr.data(),lineStr.length());
2841 if (YY_START==SkipVerbatim || YY_START==SkipCond)
2847 outputArray(yytext,(int)yyleng);
2848 g_lastCContext=YY_START;
2850 if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2851 BEGIN(SkipCComment);
2855 if (YY_START==SkipVerbatim || YY_START==SkipCond)
2861 outputArray(yytext,(int)yyleng);
2862 g_lastCPPContext=YY_START;
2863 if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2864 BEGIN(SkipCPPComment);
2872 g_expectGuard = FALSE;
2873 outputChar(*yytext);
2878 /*@ ----------------------------------------------------------------------------
2881 static int getNextChar(const QCString &expr,QCString *rest,uint &pos)
2883 //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2884 if (pos<expr.length())
2886 //printf("%c=expr()\n",expr.at(pos));
2887 return expr.at(pos++);
2889 else if (rest && !rest->isEmpty())
2892 *rest=rest->right(rest->length()-1);
2893 //printf("%c=rest\n",cc);
2899 //printf("%d=yyinput() %d\n",cc,EOF);
2904 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos)
2906 //printf("getCurrentChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2907 if (pos<expr.length())
2909 //printf("%c=expr()\n",expr.at(pos));
2910 return expr.at(pos);
2912 else if (rest && !rest->isEmpty())
2915 //printf("%c=rest\n",cc);
2921 returnCharToStream(cc);
2923 //printf("%c=yyinput()\n",cc);
2928 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c)
2930 //printf("unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2931 if (pos<expr.length())
2937 //printf("Prepending to rest!\n");
2938 char cs[2];cs[0]=c;cs[1]='\0';
2944 returnCharToStream(c);
2946 //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2949 void addSearchDir(const char *dir)
2952 if (fi.isDir()) g_pathList->append(fi.absFilePath().utf8());
2955 void initPreprocessor()
2957 g_pathList = new QStrList;
2959 g_expandedDict = new DefineDict(17);
2962 void cleanUpPreprocessor()
2964 delete g_expandedDict; g_expandedDict=0;
2965 delete g_pathList; g_pathList=0;
2966 DefineManager::deleteInstance();
2970 void preprocessFile(const char *fileName,BufStr &input,BufStr &output)
2972 printlex(yy_flex_debug, TRUE, __FILE__, fileName);
2973 uint orgOffset=output.curPos();
2974 //printf("##########################\n%s\n####################\n",
2977 g_macroExpansion = Config_getBool("MACRO_EXPANSION");
2978 g_expandOnlyPredef = Config_getBool("EXPAND_ONLY_PREDEF");
2984 g_outputBuf=&output;
2985 g_includeStack.setAutoDelete(TRUE);
2986 g_includeStack.clear();
2987 g_expandedDict->setAutoDelete(FALSE);
2988 g_expandedDict->clear();
2989 g_condStack.clear();
2990 g_condStack.setAutoDelete(TRUE);
2991 //g_fileDefineDict->clear();
2993 setFileName(fileName);
2994 g_inputFileDef = g_yyFileDef;
2995 DefineManager::instance().startContext(g_yyFileName);
2997 static bool firstTime=TRUE;
3000 // add predefined macros
3002 QStrList &predefList = Config_getList("PREDEFINED");
3003 QStrListIterator sli(predefList);
3004 for (sli.toFirst();(defStr=sli.current());++sli)
3006 QCString ds = defStr;
3007 int i_equals=ds.find('=');
3008 int i_obrace=ds.find('(');
3009 int i_cbrace=ds.find(')');
3010 bool nonRecursive = i_equals>0 && ds.at(i_equals-1)==':';
3012 if (i_obrace==0) continue; // no define name
3014 if (i_obrace<i_equals && i_cbrace<i_equals &&
3015 i_obrace!=-1 && i_cbrace!=-1 &&
3017 ) // predefined function macro definition
3019 //printf("predefined function macro '%s'\n",defStr);
3020 QRegExp reId("[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*"); // regexp matching an id
3021 QDict<int> argDict(17);
3022 argDict.setAutoDelete(TRUE);
3023 int i=i_obrace+1,p,l,count=0;
3024 // gather the formal arguments in a dictionary
3025 while (i<i_cbrace && (p=reId.match(ds,i,&l)))
3027 argDict.insert(ds.mid(p,l),new int(count++));
3030 // strip definition part
3031 QCString tmp=ds.right(ds.length()-i_equals-1);
3032 QCString definition;
3034 // substitute all occurrences of formal arguments by their
3035 // corresponding markers
3036 while ((p=reId.match(tmp,i,&l))!=-1)
3038 if (p>i) definition+=tmp.mid(i,p-i);
3040 if ((argIndex=argDict[tmp.mid(p,l)])!=0)
3043 marker.sprintf(" @%d ",*argIndex);
3048 definition+=tmp.mid(p,l);
3052 if (i<(int)tmp.length()) definition+=tmp.mid(i,tmp.length()-i);
3054 // add define definition to the dictionary of defines for this file
3055 QCString dname = ds.left(i_obrace);
3056 if (!dname.isEmpty())
3058 Define *def = new Define;
3060 def->definition = definition;
3062 def->isPredefined = TRUE;
3063 def->nonRecursive = nonRecursive;
3064 def->fileDef = g_yyFileDef;
3065 def->fileName = fileName;
3066 DefineManager::instance().addDefine(g_yyFileName,def);
3069 //printf("#define `%s' `%s' #nargs=%d\n",
3070 // def->name.data(),def->definition.data(),def->nargs);
3072 else if ((i_obrace==-1 || i_obrace>i_equals) &&
3073 (i_cbrace==-1 || i_cbrace>i_equals) &&
3074 !ds.isEmpty() && (int)ds.length()>i_equals
3075 ) // predefined non-function macro definition
3077 //printf("predefined normal macro '%s'\n",defStr);
3078 Define *def = new Define;
3079 if (i_equals==-1) // simple define without argument
3082 def->definition = "1"; // substitute occurrences by 1 (true)
3084 else // simple define with argument
3086 int ine=i_equals - (nonRecursive ? 1 : 0);
3087 def->name = ds.left(ine);
3088 def->definition = ds.right(ds.length()-i_equals-1);
3090 if (!def->name.isEmpty())
3093 def->isPredefined = TRUE;
3094 def->nonRecursive = nonRecursive;
3095 def->fileDef = g_yyFileDef;
3096 def->fileName = fileName;
3097 DefineManager::instance().addDefine(g_yyFileName,def);
3104 //printf("#define `%s' `%s' #nargs=%d\n",
3105 // def->name.data(),def->definition.data(),def->nargs);
3118 g_expectGuard = guessSection(fileName)==Entry::HEADER_SEC;
3119 g_guardName.resize(0);
3120 g_lastGuardName.resize(0);
3121 g_guardExpr.resize(0);
3126 while (!g_condStack.isEmpty())
3128 CondCtx *ctx = g_condStack.pop();
3129 QCString sectionInfo = " ";
3130 if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label %s ",ctx->sectionId.data());
3131 warn(fileName,ctx->lineNr,"Conditional section%sdoes not have "
3132 "a corresponding \\endcond command within this file.",sectionInfo.data());
3134 // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829)
3135 forceEndCondSection();
3137 // remove locally defined macros so they can be redefined in another source file
3138 //if (g_fileDefineDict->count()>0)
3140 // QDictIterator<Define> di(*g_fileDefineDict);
3142 // for (di.toFirst();(d=di.current());++di)
3144 // g_globalDefineDict->remove(di.currentKey());
3146 // g_fileDefineDict->clear();
3149 if (Debug::isFlagSet(Debug::Preprocessor))
3151 char *orgPos=output.data()+orgOffset;
3152 char *newPos=output.data()+output.curPos();
3153 Debug::print(Debug::Preprocessor,0,"Preprocessor output (size: %d bytes):\n",newPos-orgPos);
3155 Debug::print(Debug::Preprocessor,0,"---------\n00001 ");
3156 while (orgPos<newPos)
3159 if (*orgPos=='\n') Debug::print(Debug::Preprocessor,0,"%05d ",++line);
3162 Debug::print(Debug::Preprocessor,0,"\n---------\n");
3163 if (DefineManager::instance().defineContext().count()>0)
3165 Debug::print(Debug::Preprocessor,0,"Macros accessible in this file:\n");
3166 Debug::print(Debug::Preprocessor,0,"---------\n");
3167 QDictIterator<Define> di(DefineManager::instance().defineContext());
3169 for (di.toFirst();(def=di.current());++di)
3171 Debug::print(Debug::Preprocessor,0,"%s ",def->name.data());
3173 Debug::print(Debug::Preprocessor,0,"\n---------\n");
3177 Debug::print(Debug::Preprocessor,0,"No macros accessible in this file.\n");
3180 DefineManager::instance().endContext();
3181 printlex(yy_flex_debug, FALSE, __FILE__, fileName);
3184 void preFreeScanner()
3186 #if defined(YY_FLEX_SUBMINOR_VERSION)
3194 #if !defined(YY_FLEX_SUBMINOR_VERSION)
3195 extern "C" { // some bogus code to keep the compiler happy
3196 // int preYYwrap() { return 1 ; }
3197 void preYYdummy() { yy_flex_realloc(0,0); }