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 || // same number of arguments
890 (argCount>=def->nargs-1 && def->varArgs)) // variadic macro with at least as many
891 // params as the non-variadic part (see bug731985)
894 // substitution of all formal arguments
896 const QCString d=def->definition.stripWhiteSpace();
897 //printf("Macro definition: %s\n",d.data());
901 if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
903 if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
906 resExpr+="@@"; // we unescape these later
908 else if (d.at(k+1)=='-') // no-rescan marker
913 else // argument marker => read the argument number
919 // search for ## backward
920 if (l>=0 && d.at(l)=='"') l--;
921 while (l>=0 && d.at(l)==' ') l--;
922 if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
925 while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
928 // search for ## forward
930 if (l<(int)d.length() && d.at(l)=='"') l++;
931 while (l<(int)d.length() && d.at(l)==' ') l++;
932 if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
934 //printf("request key %s result %s\n",key.data(),argTable[key]->data());
935 if (key.length()>1 && (subst=argTable[key]))
937 QCString substArg=*subst;
938 //printf("substArg=`%s'\n",substArg.data());
939 // only if no ## operator is before or after the argument
940 // marker we do macro expansion.
941 if (!hash) expandExpression(substArg,0,0);
944 //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data());
946 // if the marker is inside a string (because a # was put
947 // before the macro name) we must escape " and \ characters
948 resExpr+=stringize(substArg);
952 if (hash && substArg.isEmpty())
954 resExpr+="@E"; // empty argument will be remove later on
962 resExpr+=" "+substArg+" ";
968 else // no marker, just copy
970 if (!inString && d.at(k)=='\"')
972 inString=TRUE; // entering a literal string
974 else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
976 inString=FALSE; // leaving a literal string
983 //printf("result after substitution `%s' expr=`%s'\n",
984 // result.data(),expr.mid(pos,len).data());
991 /*! returns the next identifier in string \a expr by starting at position \a p.
992 * The position of the identifier is returned (or -1 if nothing is found)
993 * and \a l is its length. Any quoted strings are skipping during the search.
995 static int getNextId(const QCString &expr,int p,int *l)
998 while (p<(int)expr.length())
1000 char c=expr.at(p++);
1001 if (isdigit(c)) // skip number
1003 while (p<(int)expr.length() && isId(expr.at(p))) p++;
1005 else if (isalpha(c) || c=='_') // read id
1008 while (p<(int)expr.length() && isId(expr.at(p))) p++;
1012 else if (c=='"') // skip string
1015 if (p<(int)expr.length()) c=expr.at(p);
1016 while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\')))
1017 // continue as long as no " is found, but ignoring \", but not \\"
1024 if (p<(int)expr.length()) ++p; // skip closing quote
1026 else if (c=='/') // skip C Comment
1028 //printf("Found C comment at p=%d\n",p);
1030 if (p<(int)expr.length())
1033 if (c=='*') // Start of C comment
1036 while (p<(int)expr.length() && !(pc=='*' && c=='/'))
1043 //printf("Found end of C comment at p=%d\n",p);
1049 /*! preforms recursive macro expansion on the string \a expr
1050 * starting at position \a pos.
1051 * May read additional characters from the input while re-scanning!
1052 * If \a expandAll is \c TRUE then all macros in the expression are
1053 * expanded, otherwise only the first is expanded.
1055 static void expandExpression(QCString &expr,QCString *rest,int pos)
1057 //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0);
1060 bool definedTest=FALSE;
1062 while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
1064 bool replaced=FALSE;
1065 macroName=expr.mid(p,l);
1066 //printf("macroName=%s\n",macroName.data());
1067 if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
1069 if (g_expandedDict->find(macroName)==0) // expand macro
1071 Define *def=DefineManager::instance().isDefined(macroName);
1072 if (definedTest) // macro name was found after defined
1074 if (def) expMacro = " 1 "; else expMacro = " 0 ";
1079 else if (def && def->nargs==-1) // simple macro
1081 // substitute the definition of the macro
1082 //printf("macro `%s'->`%s'\n",macroName.data(),def->definition.data());
1085 expMacro=def->definition.stripWhiteSpace();
1089 expMacro=" "+def->definition.stripWhiteSpace()+" ";
1091 //expMacro=def->definition.stripWhiteSpace();
1094 //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data());
1096 else if (def && def->nargs>=0) // function macro
1098 replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro);
1101 else if (macroName=="defined")
1103 //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data());
1107 if (replaced) // expand the macro and rescan the expression
1110 //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data());
1111 QCString resultExpr=expMacro;
1112 QCString restExpr=expr.right(expr.length()-len-p);
1113 processConcatOperators(resultExpr);
1114 if (def && !def->nonRecursive)
1116 g_expandedDict->insert(macroName,def);
1117 expandExpression(resultExpr,&restExpr,0);
1118 g_expandedDict->remove(macroName);
1120 expr=expr.left(p)+resultExpr+restExpr;
1122 //printf("new expression: %s\n",expr.data());
1124 else // move to the next macro name
1126 //printf("moving to the next macro old=%d new=%d\n",i,p+l);
1130 else // move to the next macro name
1132 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
1133 //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data());
1138 else // no re-scan marker found, skip the macro name
1140 //printf("skipping marked macro\n");
1146 /*! replaces all occurrences of @@@@ in \a s by @@
1147 * and removes all occurrences of @@E.
1148 * All identifiers found are replaced by 0L
1150 QCString removeIdsAndMarkers(const char *s)
1152 //printf("removeIdsAndMarkers(%s)\n",s);
1161 if (c=='@') // replace @@ with @ and remove @E
1167 else if (*(p+1)=='E')
1173 else if (isdigit(c)) // number
1179 else if (c=='d' && !inNum) // identifier starting with a `d'
1181 if (qstrncmp(p,"defined ",8)==0 || qstrncmp(p,"defined(",8)==0)
1184 p+=7; // skip defined
1190 while ((c=*p) && isId(c)) p++;
1193 else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
1197 while ((c=*p) && isId(c)) p++;
1198 if (*p=='(') // undefined function macro
1204 if (c=='(') count++;
1208 if (count==0) break;
1214 if (c=='*') // start of C comment
1216 while (*p && !(pc=='*' && c=='/')) // search end of comment
1227 else if (c=='/') // skip C comments
1231 if (c=='*') // start of C comment
1233 while (*p && !(pc=='*' && c=='/')) // search end of comment
1240 else // oops, not comment but division
1251 if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE;
1256 //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data());
1260 /*! replaces all occurrences of @@ in \a s by @
1262 * \a s only contains pairs of @@'s
1264 QCString removeMarkers(const char *s)
1275 case '@': // replace @@ with @
1284 case '/': // skip C comments
1289 if (c=='*') // start of C comment
1291 while (*p && !(pc=='*' && c=='/')) // search end of comment
1293 if (*p=='@' && *(p+1)=='@')
1300 if (*p) result+=c,p++;
1304 case '"': // skip string literals
1309 while (*p && (c!='"' || pc=='\\')) // no end quote
1314 if (*p) result+=c,p++;
1317 case '\'': // skip char literals
1322 while (*p && (c!='\'' || pc=='\\')) // no end quote
1327 if (*p) result+=c,p++;
1339 //printf("RemoveMarkers(%s)=%s\n",s,result.data());
1343 /*! compute the value of the expression in string \a expr.
1344 * If needed the function may read additional characters from the input.
1347 bool computeExpression(const QCString &expr)
1350 expandExpression(e,0,0);
1351 //printf("after expansion `%s'\n",e.data());
1352 e = removeIdsAndMarkers(e);
1353 if (e.isEmpty()) return FALSE;
1354 //printf("parsing `%s'\n",e.data());
1355 return parseconstexp(g_yyFileName,g_yyLineNr,e);
1358 /*! expands the macro definition in \a name
1359 * If needed the function may read additional characters from the input
1362 QCString expandMacro(const QCString &name)
1365 expandExpression(n,0,0);
1367 //printf("expandMacro `%s'->`%s'\n",name.data(),n.data());
1373 Define *def=new Define;
1374 def->name = g_defName;
1375 def->definition = g_defText.stripWhiteSpace();
1376 def->nargs = g_defArgs;
1377 def->fileName = g_yyFileName;
1378 def->fileDef = g_yyFileDef;
1379 def->lineNr = g_yyLineNr-g_yyMLines;
1380 def->columnNr = g_yyColNr;
1381 def->varArgs = g_defVarArgs;
1382 //printf("newDefine: %s %s file: %s\n",def->name.data(),def->definition.data(),
1383 // def->fileDef ? def->fileDef->name().data() : def->fileName.data());
1384 //printf("newDefine: `%s'->`%s'\n",def->name.data(),def->definition.data());
1385 if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name])
1387 def->isPredefined=TRUE;
1394 if (g_skip) return; // do not add this define as it is inside a
1395 // conditional section (cond command) that is disabled.
1396 if (!Doxygen::gatherDefines) return;
1398 //printf("addDefine %s %s\n",g_defName.data(),g_defArgsStr.data());
1399 //ArgumentList *al = new ArgumentList;
1400 //stringToArgumentList(g_defArgsStr,al);
1401 MemberDef *md=new MemberDef(
1402 g_yyFileName,g_yyLineNr-g_yyMLines,g_yyColNr,
1403 "#define",g_defName,g_defArgsStr,0,
1404 Public,Normal,FALSE,Member,MemberType_Define,0,0);
1405 if (!g_defArgsStr.isEmpty())
1407 ArgumentList *argList = new ArgumentList;
1408 //printf("addDefine() g_defName=`%s' g_defArgsStr=`%s'\n",g_defName.data(),g_defArgsStr.data());
1409 stringToArgumentList(g_defArgsStr,argList);
1410 md->setArgumentList(argList);
1412 //printf("Setting initializer for `%s' to `%s'\n",g_defName.data(),g_defText.data());
1413 int l=g_defLitText.find('\n');
1414 if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\")
1416 // strip first line if it only contains a slash
1417 g_defLitText = g_defLitText.right(g_defLitText.length()-l-1);
1421 // align the items on the first line with the items on the second line
1423 const char *p=g_defLitText.data()+k;
1425 while ((c=*p++) && (c==' ' || c=='\t')) k++;
1426 g_defLitText=g_defLitText.mid(l+1,k-l-1)+g_defLitText.stripWhiteSpace();
1428 md->setInitializer(g_defLitText.stripWhiteSpace());
1430 //printf("pre.l: md->setFileDef(%p)\n",g_inputFileDef);
1431 md->setFileDef(g_inputFileDef);
1432 md->setDefinition("#define "+g_defName);
1434 MemberName *mn=Doxygen::functionNameSDict->find(g_defName);
1437 mn = new MemberName(g_defName);
1438 Doxygen::functionNameSDict->append(g_defName,mn);
1443 g_yyFileDef->insertMember(md);
1447 //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine());
1450 static inline void outputChar(char c)
1452 if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addChar(c);
1455 static inline void outputArray(const char *a,int len)
1457 if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addArray(a,len);
1460 static void readIncludeFile(const QCString &inc)
1462 static bool searchIncludes = Config_getBool("SEARCH_INCLUDES");
1465 // find the start of the include file name
1466 while (i<inc.length() &&
1467 (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
1471 // was it a local include?
1472 bool localInclude = s>0 && inc.at(s-1)=='"';
1474 // find the end of the include file name
1475 while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
1477 if (s<inc.length() && i>s) // valid include file name found
1479 // extract include path+name
1480 QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
1482 QCString dosExt = incFileName.right(4);
1483 if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb")
1485 // skip imported binary files (e.g. M$ type libraries)
1489 QCString oldFileName = g_yyFileName;
1490 FileDef *oldFileDef = g_yyFileDef;
1491 int oldLineNr = g_yyLineNr;
1492 //printf("Searching for `%s'\n",incFileName.data());
1494 // absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336)
1495 QCString absIncFileName = incFileName;
1497 QFileInfo fi(g_yyFileName);
1500 QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName;
1501 QFileInfo fi2(absName);
1504 absIncFileName=fi2.absFilePath().utf8();
1506 else if (searchIncludes) // search in INCLUDE_PATH as well
1508 QStrList &includePath = Config_getList("INCLUDE_PATH");
1509 char *s=includePath.first();
1513 if (fi.exists() && fi.isDir())
1515 QCString absName = QCString(fi.absFilePath().utf8())+"/"+incFileName;
1516 //printf("trying absName=%s\n",absName.data());
1517 QFileInfo fi2(absName);
1520 absIncFileName=fi2.absFilePath().utf8();
1523 //printf( "absIncFileName = %s\n", absIncFileName.data() );
1525 s=includePath.next();
1528 //printf( "absIncFileName = %s\n", absIncFileName.data() );
1531 DefineManager::instance().addInclude(g_yyFileName,absIncFileName);
1532 DefineManager::instance().addFileToContext(absIncFileName);
1534 // findFile will overwrite g_yyFileDef if found
1536 bool alreadyIncluded = FALSE;
1537 //printf("calling findFile(%s)\n",incFileName.data());
1538 if ((fs=findFile(incFileName,localInclude,alreadyIncluded))) // see if the include file can be found
1540 //printf("Found include file!\n");
1541 if (Debug::isFlagSet(Debug::Preprocessor))
1543 for (i=0;i<g_includeStack.count();i++)
1545 Debug::print(Debug::Preprocessor,0," ");
1547 //msg("#include %s: parsing...\n",incFileName.data());
1551 // add include dependency to the file in which the #include was found
1553 // change to absolute name for bug 641336
1554 FileDef *incFd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1555 oldFileDef->addIncludeDependency(ambig ? 0 : incFd,incFileName,localInclude,g_isImported,FALSE);
1556 // add included by dependency
1559 //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data());
1560 g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1563 else if (g_inputFileDef)
1565 g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1567 fs->bufState = YY_CURRENT_BUFFER;
1568 fs->lineNr = oldLineNr;
1569 fs->fileName = oldFileName;
1570 // push the state on the stack
1571 g_includeStack.push(fs);
1572 // set the scanner to the include file
1574 // Deal with file changes due to
1575 // #include's within { .. } blocks
1576 QCString lineStr(g_yyFileName.length()+20);
1577 lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data());
1578 outputArray(lineStr.data(),lineStr.length());
1580 DBG_CTX((stderr,"Switching to include file %s\n",incFileName.data()));
1582 g_inputBuf = &fs->fileBuf;
1584 yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE));
1588 //printf(" calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded);
1592 //QCString absPath = incFileName;
1593 //if (QDir::isRelativePath(incFileName))
1595 // absPath = QDir::cleanDirPath(oldFileDef->getPath()+"/"+incFileName);
1596 // //printf("%s + %s -> resolved path %s\n",oldFileDef->getPath().data(),incFileName.data(),absPath.data());
1599 // change to absolute name for bug 641336
1600 FileDef *fd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig);
1601 //printf("%s::findFileDef(%s)=%p\n",oldFileDef->name().data(),incFileName.data(),fd);
1602 // add include dependency to the file in which the #include was found
1603 oldFileDef->addIncludeDependency(ambig ? 0 : fd,incFileName,localInclude,g_isImported,FALSE);
1604 // add included by dependency
1607 //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig);
1608 fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
1611 else if (g_inputFileDef)
1613 g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE);
1615 if (Debug::isFlagSet(Debug::Preprocessor))
1617 if (alreadyIncluded)
1619 Debug::print(Debug::Preprocessor,0,"#include %s: already included! skipping...\n",incFileName.data());
1623 Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",incFileName.data());
1625 //printf("error: include file %s not found\n",yytext);
1627 if (g_curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... }
1629 warn(g_yyFileName,g_yyLineNr,"include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data());
1635 /* ----------------------------------------------------------------- */
1637 static void startCondSection(const char *sectId)
1639 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1641 bool expResult = prs.parse(g_yyFileName,g_yyLineNr,sectId);
1642 g_condStack.push(new CondCtx(g_yyLineNr,sectId,g_skip));
1647 //printf(" expResult=%d skip=%d\n",expResult,g_skip);
1650 static void endCondSection()
1652 if (g_condStack.isEmpty())
1658 CondCtx *ctx = g_condStack.pop();
1661 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1664 static void forceEndCondSection()
1666 while (!g_condStack.isEmpty())
1673 static QCString escapeAt(const char *text)
1682 if (c=='@') result+="@@"; else result+=c;
1688 static char resolveTrigraph(char c)
1692 case '=': return '#';
1693 case '/': return '\\';
1694 case '\'': return '^';
1695 case '(': return '[';
1696 case ')': return ']';
1697 case '!': return '|';
1698 case '<': return '{';
1699 case '>': return '}';
1700 case '-': return '~';
1705 /* ----------------------------------------------------------------- */
1708 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
1710 static int yyread(char *buf,int max_size)
1712 int bytesInBuf = g_inputBuf->curPos()-g_inputBufPos;
1713 int bytesToCopy = QMIN(max_size,bytesInBuf);
1714 memcpy(buf,g_inputBuf->data()+g_inputBufPos,bytesToCopy);
1715 g_inputBufPos+=bytesToCopy;
1719 /* ----------------------------------------------------------------- */
1723 ID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
1726 CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
1771 <*>"??"[=/'()!<>-] { // Trigraph
1772 unput(resolveTrigraph(yytext[2]));
1774 <Start>^{B}*"#" { BEGIN(Command); g_yyColNr+=yyleng; g_yyMLines=0;}
1776 outputArray(yytext,(int)yyleng);
1779 <Start>^{B}*[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]+{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors?
1781 for (i=(int)yyleng-1;i>=0;i--)
1787 <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
1788 <Start>^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\)\n]*")"{B}*\n { // function like macro
1789 static bool skipFuncMacros = Config_getBool("SKIP_FUNCTION_MACROS");
1790 QCString name(yytext);
1791 name=name.left(name.find('(')).stripWhiteSpace();
1794 if (skipFuncMacros &&
1795 name!="Q_PROPERTY" &&
1797 (g_includeStack.isEmpty() || g_curlyCount>0) &&
1799 (def=DefineManager::instance().isDefined(name)) &&
1800 /*macroIsAccessible(def) &&*/
1801 (!g_expandOnlyPredef || def->isPredefined)
1811 for (i=(int)yyleng-1;i>=0;i--)
1818 <CopyLine>"extern"{BN}{0,80}"\"C\""*{BN}{0,80}"{" {
1819 QCString text=yytext;
1820 g_yyLineNr+=text.contains('\n');
1821 outputArray(yytext,(int)yyleng);
1823 <CopyLine>"{" { // count brackets inside the main file
1824 if (g_includeStack.isEmpty())
1828 outputChar(*yytext);
1830 <CopyLine>"}" { // count brackets inside the main file
1831 if (g_includeStack.isEmpty() && g_curlyCount>0)
1835 outputChar(*yytext);
1837 <CopyLine>"'"\\[0-7]{1,3}"'" {
1838 outputArray(yytext,(int)yyleng);
1840 <CopyLine>"'"\\."'" {
1841 outputArray(yytext,(int)yyleng);
1844 outputArray(yytext,(int)yyleng);
1847 outputChar(*yytext);
1848 BEGIN( CopyString );
1850 <CopyString>[^\"\\\r\n]+ {
1851 outputArray(yytext,(int)yyleng);
1854 outputArray(yytext,(int)yyleng);
1857 outputChar(*yytext);
1860 <CopyLine>{ID}/{BN}{0,80}"(" {
1861 g_expectGuard = FALSE;
1863 //def=g_globalDefineDict->find(yytext);
1864 //def=DefineManager::instance().isDefined(yytext);
1865 //printf("Search for define %s found=%d g_includeStack.isEmpty()=%d "
1866 // "g_curlyCount=%d g_macroExpansion=%d g_expandOnlyPredef=%d "
1867 // "isPreDefined=%d\n",yytext,def ? 1 : 0,
1868 // g_includeStack.isEmpty(),g_curlyCount,g_macroExpansion,g_expandOnlyPredef,
1869 // def ? def->isPredefined : -1
1871 if ((g_includeStack.isEmpty() || g_curlyCount>0) &&
1873 (def=DefineManager::instance().isDefined(yytext)) &&
1874 /*(def->isPredefined || macroIsAccessible(def)) && */
1875 (!g_expandOnlyPredef || def->isPredefined)
1878 //printf("Found it! #args=%d\n",def->nargs);
1880 g_defArgsStr=yytext;
1881 if (def->nargs==-1) // no function macro
1883 QCString result = def->isPredefined ? def->definition : expandMacro(g_defArgsStr);
1884 outputArray(result,result.length());
1886 else // zero or more arguments
1888 g_findDefArgContext = CopyLine;
1889 BEGIN(FindDefineArgs);
1894 outputArray(yytext,(int)yyleng);
1899 if ((g_includeStack.isEmpty() || g_curlyCount>0) &&
1901 (def=DefineManager::instance().isDefined(yytext)) &&
1903 /*(def->isPredefined || macroIsAccessible(def)) &&*/
1904 (!g_expandOnlyPredef || def->isPredefined)
1907 QCString result=def->isPredefined ? def->definition : expandMacro(yytext);
1908 outputArray(result,result.length());
1912 outputArray(yytext,(int)yyleng);
1915 <CopyLine>"\\"\r?/\n { // strip line continuation characters
1918 outputChar(*yytext);
1926 <FindDefineArgs>"(" {
1930 <FindDefineArgs>")" {
1933 if (g_roundCount==0)
1935 QCString result=expandMacro(g_defArgsStr);
1936 //printf("g_defArgsStr=`%s'->`%s'\n",g_defArgsStr.data(),result.data());
1937 if (g_findDefArgContext==CopyLine)
1939 outputArray(result,result.length());
1940 BEGIN(g_findDefArgContext);
1942 else // g_findDefArgContext==IncludeID
1944 readIncludeFile(result);
1951 <FindDefineArgs>")"{B}*"(" {
1952 g_defArgsStr+=yytext;
1955 <FindDefineArgs>{CHARLIT} {
1956 g_defArgsStr+=yytext;
1958 <FindDefineArgs>"/*"[*]? {
1959 g_defArgsStr+=yytext;
1960 BEGIN(ArgCopyCComment);
1962 <FindDefineArgs>\" {
1963 g_defArgsStr+=*yytext;
1966 <FindDefineArgs>\n {
1971 <FindDefineArgs>"@" {
1975 g_defArgsStr+=*yytext;
1977 <ArgCopyCComment>[^*\n]+ {
1978 g_defArgsStr+=yytext;
1980 <ArgCopyCComment>"*/" {
1981 g_defArgsStr+=yytext;
1982 BEGIN(FindDefineArgs);
1984 <ArgCopyCComment>\n {
1989 <ArgCopyCComment>. {
1990 g_defArgsStr+=yytext;
1993 g_defArgsStr+=*yytext;
1994 BEGIN(FindDefineArgs);
1996 <ReadString>"//"|"/*" {
1997 g_defArgsStr+=yytext;
2000 g_defArgsStr+=yytext;
2003 g_defArgsStr+=*yytext;
2005 <Command>("include"|"import"){B}+/{ID} {
2006 g_isImported = yytext[1]=='m';
2007 if (g_macroExpansion)
2010 <Command>("include"|"import"){B}*[<"] {
2011 g_isImported = yytext[1]=='m';
2013 c[0]=yytext[yyleng-1];c[1]='\0';
2017 <Command>("cmake")?"define"{B}+ {
2018 //printf("!!!DefName\n");
2022 <Command>"ifdef"/{B}*"(" {
2024 g_guardExpr.resize(0);
2025 BEGIN(DefinedExpr2);
2027 <Command>"ifdef"/{B}+ {
2028 //printf("Pre.l: ifdef\n");
2030 g_guardExpr.resize(0);
2031 BEGIN(DefinedExpr1);
2033 <Command>"ifndef"/{B}*"(" {
2036 BEGIN(DefinedExpr2);
2038 <Command>"ifndef"/{B}+ {
2041 BEGIN(DefinedExpr1);
2043 <Command>"if"/[ \t(!] {
2045 g_guardExpr.resize(0);
2048 <Command>("elif"|"else"{B}*"if")/[ \t(!] {
2049 if (!otherCaseDone())
2051 g_guardExpr.resize(0);
2057 BEGIN(SkipCPPBlock);
2060 <Command>"else"/[^a-z_A-Z0-9\x80-\xFF] {
2061 //printf("else g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2062 if (otherCaseDone())
2065 BEGIN(SkipCPPBlock);
2070 //g_levelGuard[g_level-1]=TRUE;
2073 <Command>"undef"{B}+ {
2076 <Command>("elif"|"else"{B}*"if")/[ \t(!] {
2077 if (!otherCaseDone())
2079 g_guardExpr.resize(0);
2083 <Command>"endif"/[^a-z_A-Z0-9\x80-\xFF] {
2084 //printf("Pre.l: #endif\n");
2087 <Command,IgnoreLine>\n {
2092 <Command>"pragma"{B}+"once" {
2093 g_expectGuard = FALSE;
2095 <Command>{ID} { // unknown directive
2098 <IgnoreLine>\\[\r]?\n {
2103 <Command>. {g_yyColNr+=yyleng;}
2106 if ((def=DefineManager::instance().isDefined(yytext))
2107 /*&& !def->isPredefined*/
2108 && !def->nonRecursive
2111 //printf("undefining %s\n",yytext);
2121 <Guard>"defined"/{B}*"(" {
2122 BEGIN(DefinedExpr2);
2124 <Guard>"defined"/{B}+ {
2125 BEGIN(DefinedExpr1);
2127 <Guard>{ID} { g_guardExpr+=yytext; }
2128 <Guard>. { g_guardExpr+=*yytext; }
2131 //printf("Guard: `%s'\n",
2132 // g_guardExpr.data());
2133 bool guard=computeExpression(g_guardExpr);
2135 //printf("if g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]);
2143 BEGIN(SkipCPPBlock);
2146 <DefinedExpr1,DefinedExpr2>\\\n { g_yyLineNr++; outputChar('\n'); }
2147 <DefinedExpr1>{ID} {
2148 if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2149 g_guardExpr+=" 1L ";
2151 g_guardExpr+=" 0L ";
2152 g_lastGuardName=yytext;
2155 <DefinedExpr2>{ID} {
2156 if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext)
2157 g_guardExpr+=" 1L ";
2159 g_guardExpr+=" 0L ";
2160 g_lastGuardName=yytext;
2162 <DefinedExpr1,DefinedExpr2>\n { // should not happen, handle anyway
2165 BEGIN(SkipCPPBlock);
2170 <DefinedExpr1,DefinedExpr2>.
2171 <SkipCPPBlock>^{B}*"#" { BEGIN(SkipCommand); }
2172 <SkipCPPBlock>^{B}*/[^#] { BEGIN(SkipLine); }
2173 <SkipCPPBlock>\n { g_yyLineNr++; outputChar('\n'); }
2175 <SkipCommand>"if"(("n")?("def"))?/[ \t(!] {
2178 //printf("#if... depth=%d\n",g_ifcount);
2180 <SkipCommand>"else" {
2181 //printf("Else! g_ifcount=%d otherCaseDone=%d\n",g_ifcount,otherCaseDone());
2182 if (g_ifcount==0 && !otherCaseDone())
2189 <SkipCommand>("elif"|"else"{B}*"if")/[ \t(!] {
2192 if (!otherCaseDone())
2194 g_guardExpr.resize(0);
2195 g_lastGuardName.resize(0);
2200 BEGIN(SkipCPPBlock);
2204 <SkipCommand>"endif" {
2205 g_expectGuard = FALSE;
2216 BEGIN(SkipCPPBlock);
2218 <SkipCommand>{ID} { // unknown directive
2223 <SkipLine>{CHARLIT} { }
2228 <SkipString>"//"/[^\n]* {
2230 <SkipLine,SkipCommand,SkipCPPBlock>"//"[^\n]* {
2231 g_lastCPPContext=YY_START;
2232 BEGIN(RemoveCPPComment);
2234 <SkipString>"/*"/[^\n]* {
2236 <SkipLine,SkipCommand,SkipCPPBlock>"/*"/[^\n]* {
2237 g_lastCContext=YY_START;
2238 BEGIN(RemoveCComment);
2243 BEGIN(SkipCPPBlock);
2245 <SkipString>[^"\\\n]+ { }
2251 <IncludeID>{ID}{B}*/"(" {
2254 g_defArgsStr=yytext;
2255 g_findDefArgContext = IncludeID;
2256 BEGIN(FindDefineArgs);
2260 readIncludeFile(expandMacro(yytext));
2263 <Include>[^\">\n]+[\">] {
2265 readIncludeFile(g_incName);
2275 <EndImport>[^\\\n]*/\n {
2278 <EndImport>\\[\r]?"\n" {
2284 <DefName>{ID}/("\\\n")*"(" { // define with argument
2285 //printf("Define() `%s'\n",yytext);
2286 g_argDict = new QDict<int>(31);
2287 g_argDict->setAutoDelete(TRUE);
2289 g_defArgsStr.resize(0);
2290 g_defText.resize(0);
2291 g_defLitText.resize(0);
2293 g_defVarArgs = FALSE;
2294 g_defExtraSpacing.resize(0);
2297 <DefName>{ID}{B}+"1"/[ \r\t\n] { // special case: define with 1 -> can be "guard"
2298 //printf("Define `%s'\n",yytext);
2301 g_defArgsStr.resize(0);
2303 g_defName = g_defName.left(g_defName.length()-1).stripWhiteSpace();
2304 g_defVarArgs = FALSE;
2305 //printf("Guard check: %s!=%s || %d\n",
2306 // g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2307 if (g_curlyCount>0 || g_defName!=g_lastGuardName || !g_expectGuard)
2308 { // define may appear in the output
2309 QCString tmp=(QCString)"#define "+g_defName;
2310 outputArray(tmp.data(),tmp.length());
2312 g_insideComment=FALSE;
2313 g_lastGuardName.resize(0);
2318 else // define is a guard => hide
2320 //printf("Found a guard %s\n",yytext);
2321 g_defText.resize(0);
2322 g_defLitText.resize(0);
2325 g_expectGuard=FALSE;
2327 <DefName>{ID}/{B}*"\n" { // empty define
2331 g_defArgsStr.resize(0);
2332 g_defText.resize(0);
2333 g_defLitText.resize(0);
2334 g_defVarArgs = FALSE;
2335 //printf("Guard check: %s!=%s || %d\n",
2336 // g_defName.data(),g_lastGuardName.data(),g_expectGuard);
2337 if (g_curlyCount>0 || g_defName!=g_lastGuardName || !g_expectGuard)
2338 { // define may appear in the output
2339 QCString tmp=(QCString)"#define "+g_defName;
2340 outputArray(tmp.data(),tmp.length());
2342 g_insideComment=FALSE;
2343 if (g_insideCS) g_defText="1"; // for C#, use "1" as define text
2346 else // define is a guard => hide
2348 //printf("Found a guard %s\n",yytext);
2349 g_guardName = yytext;
2350 g_lastGuardName.resize(0);
2353 g_expectGuard=FALSE;
2355 <DefName>{ID}/{B}* { // define with content
2356 //printf("Define `%s'\n",yytext);
2359 g_defArgsStr.resize(0);
2360 g_defText.resize(0);
2361 g_defLitText.resize(0);
2363 g_defVarArgs = FALSE;
2364 QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr;
2365 outputArray(tmp.data(),tmp.length());
2367 g_insideComment=FALSE;
2371 g_defExtraSpacing+="\n";
2374 <DefineArg>","{B}* { g_defArgsStr+=yytext; }
2375 <DefineArg>"("{B}* { g_defArgsStr+=yytext; }
2376 <DefineArg>{B}*")"{B}* {
2377 g_defArgsStr+=yytext;
2378 QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr+g_defExtraSpacing;
2379 outputArray(tmp.data(),tmp.length());
2381 g_insideComment=FALSE;
2384 <DefineArg>"..." { // Variadic macro
2385 g_defVarArgs = TRUE;
2386 g_defArgsStr+=yytext;
2387 g_argDict->insert("__VA_ARGS__",new int(g_defArgs));
2390 <DefineArg>{ID}{B}*("..."?) {
2391 //printf("Define addArg(%s)\n",yytext);
2392 QCString argName=yytext;
2393 g_defVarArgs = yytext[yyleng-1]=='.';
2394 if (g_defVarArgs) // strip ellipsis
2396 argName=argName.left(argName.length()-3);
2398 argName = argName.stripWhiteSpace();
2399 g_defArgsStr+=yytext;
2400 g_argDict->insert(argName,new int(g_defArgs));
2404 <DefineText>"/ **"|"/ *!" {
2406 g_defLitText+=yytext;
2407 g_insideComment=TRUE;
2411 g_defLitText+=yytext;
2412 g_insideComment=FALSE;
2415 <DefineText>"/*"[!*]? {
2417 g_defLitText+=yytext;
2418 g_lastCContext=YY_START;
2420 BEGIN(CopyCComment);
2422 <DefineText>"//"[!/]? {
2423 outputArray(yytext,(int)yyleng);
2424 g_lastCPPContext=YY_START;
2426 BEGIN(SkipCPPComment);
2428 <SkipCComment>[/]?"*/" {
2429 if (yytext[0]=='/') outputChar('/');
2430 outputChar('*');outputChar('/');
2431 if (--g_commentCount<=0)
2433 if (g_lastCContext==Start)
2434 // small hack to make sure that ^... rule will
2435 // match when going to Start... Example: "/*...*/ some stuff..."
2437 YY_CURRENT_BUFFER->yy_at_bol=1;
2439 BEGIN(g_lastCContext);
2442 <SkipCComment>"//"("/")* {
2443 outputArray(yytext,(int)yyleng);
2445 <SkipCComment>"/*" {
2446 outputChar('/');outputChar('*');
2449 <SkipCComment>[\\@][\\@]("f{"|"f$"|"f[") {
2450 outputArray(yytext,(int)yyleng);
2452 <SkipCComment>"~~~"[~]* {
2453 static bool markdownSupport = Config_getBool("MARKDOWN_SUPPORT");
2454 if (!markdownSupport)
2460 outputArray(yytext,(int)yyleng);
2462 BEGIN(SkipVerbatim);
2465 <SkipCComment>[\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ {
2466 outputArray(yytext,(int)yyleng);
2467 g_yyLineNr+=QCString(yytext).contains('\n');
2469 <SkipCComment>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ {
2470 outputArray(yytext,(int)yyleng);
2471 g_yyLineNr+=QCString(yytext).contains('\n');
2479 QCString bn=&yytext[1];
2480 int i = bn.find('{'); // for \code{.c}
2481 if (i!=-1) bn=bn.left(i);
2482 g_blockName=bn.stripWhiteSpace();
2484 BEGIN(SkipVerbatim);
2486 <SkipCComment,SkipCPPComment>[\\@][\\@]"cond"[ \t]+ { // escaped @cond
2487 outputArray(yytext,(int)yyleng);
2489 <SkipCPPComment>[\\@]"cond"[ \t]+ { // conditional section
2494 <SkipCComment>[\\@]"cond"[ \t]+ { // conditional section
2499 <CondLineC,CondLineCpp>[!()&| \ta-z_A-Z0-9\x80-\xFF.\-]+ {
2500 startCondSection(yytext);
2503 if (YY_START==CondLineC)
2506 outputArray("*/",2);
2520 <CondLineC,CondLineCpp>. { // non-guard character
2522 startCondSection(" ");
2525 if (YY_START==CondLineC)
2528 outputArray("*/",2);
2542 <SkipCComment,SkipCPPComment>[\\@]"cond"[ \t\r]*/\n { // no guard
2543 if (YY_START==SkipCComment)
2547 outputArray("*/",2);
2554 startCondSection(" ");
2557 <SkipCond>\n { g_yyLineNr++; outputChar('\n'); }
2559 <SkipCond>[^\/\!*\\@\n]+ { }
2560 <SkipCond>"//"[/!] { g_ccomment=FALSE; }
2561 <SkipCond>"/*"[*!] { g_ccomment=TRUE; }
2562 <SkipCond,SkipCComment,SkipCPPComment>[\\@][\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2565 outputArray(yytext,(int)yyleng);
2568 <SkipCond>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2569 bool oldSkip = g_skip;
2571 if (oldSkip && !g_skip)
2575 outputArray("/** ",4);
2580 <SkipCComment,SkipCPPComment>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
2581 bool oldSkip = g_skip;
2583 if (oldSkip && !g_skip)
2588 <SkipVerbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}") { /* end of verbatim block */
2589 outputArray(yytext,(int)yyleng);
2590 if (yytext[1]=='f' && g_blockName=="f")
2592 BEGIN(SkipCComment);
2594 else if (&yytext[4]==g_blockName)
2596 BEGIN(SkipCComment);
2599 <SkipVerbatim>"~~~"[~]* {
2600 outputArray(yytext,(int)yyleng);
2601 if (g_fenceSize==yyleng)
2603 BEGIN(SkipCComment);
2606 <SkipVerbatim>"*/"|"/*" {
2607 outputArray(yytext,(int)yyleng);
2609 <SkipCComment,SkipVerbatim>[^*\\@\x06~\n\/]+ {
2610 outputArray(yytext,(int)yyleng);
2612 <SkipCComment,SkipVerbatim>\n {
2616 <SkipCComment,SkipVerbatim>. {
2617 outputChar(*yytext);
2619 <CopyCComment>[^*a-z_A-Z\x80-\xFF\n]+ {
2620 g_defLitText+=yytext;
2621 g_defText+=escapeAt(yytext);
2623 <CopyCComment>"*/" {
2624 g_defLitText+=yytext;
2626 BEGIN(g_lastCContext);
2631 g_defLitText+=yytext;
2634 <RemoveCComment>"*/"{B}*"#" { // see bug 594021 for a usecase for this rule
2635 if (g_lastCContext==SkipCPPBlock)
2644 <RemoveCComment>"*/" { BEGIN(g_lastCContext); }
2645 <RemoveCComment>"//"
2646 <RemoveCComment>"/*"
2647 <RemoveCComment>[^*\x06\n]+
2648 <RemoveCComment>\n { g_yyLineNr++; outputChar('\n'); }
2650 <SkipCPPComment>[^\n\/\\@]+ {
2651 outputArray(yytext,(int)yyleng);
2653 <SkipCPPComment,RemoveCPPComment>\n {
2655 BEGIN(g_lastCPPContext);
2657 <SkipCPPComment>"/*" {
2658 outputChar('/');outputChar('*');
2660 <SkipCPPComment>"//" {
2661 outputChar('/');outputChar('/');
2663 <SkipCPPComment>[^\x06\@\\\n]+ {
2664 outputArray(yytext,(int)yyleng);
2667 outputChar(*yytext);
2669 <RemoveCPPComment>"/*"
2670 <RemoveCPPComment>"//"
2671 <RemoveCPPComment>[^\x06\n]+
2675 g_defLitText+=yytext;
2677 <DefineText,CopyCComment>{ID} {
2678 g_defLitText+=yytext;
2686 if ((n=(*g_argDict)[yytext]))
2688 //if (!g_quoteArg) g_defText+=' ';
2691 numStr.sprintf("%d",*n);
2693 //if (!g_quoteArg) g_defText+=' ';
2711 g_defLitText+=yytext;
2714 <DefineText>\\[\r]?\n {
2715 g_defLitText+=yytext;
2722 QCString comment=extractTrailingComment(g_defLitText);
2723 g_defLitText+=yytext;
2724 if (!comment.isEmpty())
2726 outputArray(comment,comment.length());
2727 g_defLitText=g_defLitText.left(g_defLitText.length()-comment.length()-1);
2731 //printf("Define name=`%s' text=`%s' litTexti=`%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data());
2732 if (g_includeStack.isEmpty() || g_curlyCount>0)
2736 def=DefineManager::instance().isDefined(g_defName);
2737 if (def==0) // new define
2739 //printf("new define '%s'!\n",g_defName.data());
2740 Define *nd = newDefine();
2741 DefineManager::instance().addDefine(g_yyFileName,nd);
2743 // also add it to the local file list if it is a source file
2744 //if (g_isSource && g_includeStack.isEmpty())
2746 // g_fileDefineDict->insert(g_defName,nd);
2749 else if (def /*&& macroIsAccessible(def)*/)
2750 // name already exists
2752 //printf("existing define!\n");
2753 //printf("define found\n");
2754 if (def->undef) // undefined name
2757 def->name = g_defName;
2758 def->definition = g_defText.stripWhiteSpace();
2759 def->nargs = g_defArgs;
2760 def->fileName = g_yyFileName.copy();
2761 def->lineNr = g_yyLineNr-g_yyMLines;
2762 def->columnNr = g_yyColNr;
2766 //printf("error: define %s is defined more than once!\n",g_defName.data());
2769 delete g_argDict; g_argDict=0;
2772 g_lastGuardName.resize(0);
2775 <DefineText>{B}* { g_defText += ' '; g_defLitText+=yytext; }
2776 <DefineText>{B}*"##"{B}* { g_defText += "##"; g_defLitText+=yytext; }
2777 <DefineText>"@" { g_defText += "@@"; g_defLitText+=yytext; }
2779 g_defText += *yytext;
2780 g_defLitText+=yytext;
2781 if (!g_insideComment)
2783 BEGIN(SkipDoubleQuote);
2786 <DefineText>\' { g_defText += *yytext;
2787 g_defLitText+=yytext;
2788 if (!g_insideComment)
2790 BEGIN(SkipSingleQuote);
2793 <SkipDoubleQuote>"//"[/]? { g_defText += yytext; g_defLitText+=yytext; }
2794 <SkipDoubleQuote>"/*" { g_defText += yytext; g_defLitText+=yytext; }
2795 <SkipDoubleQuote>\" {
2796 g_defText += *yytext; g_defLitText+=yytext;
2799 <SkipSingleQuote,SkipDoubleQuote>\\. {
2800 g_defText += yytext; g_defLitText+=yytext;
2802 <SkipSingleQuote>\' {
2803 g_defText += *yytext; g_defLitText+=yytext;
2806 <SkipDoubleQuote>. { g_defText += *yytext; g_defLitText+=yytext; }
2807 <SkipSingleQuote>. { g_defText += *yytext; g_defLitText+=yytext; }
2808 <DefineText>. { g_defText += *yytext; g_defLitText+=yytext; }
2810 DBG_CTX((stderr,"End of include file\n"));
2811 //printf("Include stack depth=%d\n",g_includeStack.count());
2812 if (g_includeStack.isEmpty())
2814 DBG_CTX((stderr,"Terminating scanner!\n"));
2819 FileState *fs=g_includeStack.pop();
2820 //fileDefineCache->merge(g_yyFileName,fs->fileName);
2821 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
2822 yy_switch_to_buffer( fs->bufState );
2823 yy_delete_buffer( oldBuf );
2824 g_yyLineNr = fs->lineNr;
2825 //preYYin = fs->oldYYin;
2826 g_inputBuf = fs->oldFileBuf;
2827 g_inputBufPos = fs->oldFileBufPos;
2828 setFileName(fs->fileName);
2829 DBG_CTX((stderr,"######## FileName %s\n",g_yyFileName.data()));
2831 // Deal with file changes due to
2832 // #include's within { .. } blocks
2833 QCString lineStr(15+g_yyFileName.length());
2834 lineStr.sprintf("# %d \"%s\" 2",g_yyLineNr,g_yyFileName.data());
2835 outputArray(lineStr.data(),lineStr.length());
2842 if (YY_START==SkipVerbatim || YY_START==SkipCond)
2848 outputArray(yytext,(int)yyleng);
2849 g_lastCContext=YY_START;
2851 if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2852 BEGIN(SkipCComment);
2856 if (YY_START==SkipVerbatim || YY_START==SkipCond)
2862 outputArray(yytext,(int)yyleng);
2863 g_lastCPPContext=YY_START;
2864 if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented!
2865 BEGIN(SkipCPPComment);
2873 g_expectGuard = FALSE;
2874 outputChar(*yytext);
2879 /*@ ----------------------------------------------------------------------------
2882 static int getNextChar(const QCString &expr,QCString *rest,uint &pos)
2884 //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2885 if (pos<expr.length())
2887 //printf("%c=expr()\n",expr.at(pos));
2888 return expr.at(pos++);
2890 else if (rest && !rest->isEmpty())
2893 *rest=rest->right(rest->length()-1);
2894 //printf("%c=rest\n",cc);
2900 //printf("%d=yyinput() %d\n",cc,EOF);
2905 static int getCurrentChar(const QCString &expr,QCString *rest,uint pos)
2907 //printf("getCurrentChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos);
2908 if (pos<expr.length())
2910 //printf("%c=expr()\n",expr.at(pos));
2911 return expr.at(pos);
2913 else if (rest && !rest->isEmpty())
2916 //printf("%c=rest\n",cc);
2922 returnCharToStream(cc);
2924 //printf("%c=yyinput()\n",cc);
2929 static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c)
2931 //printf("unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2932 if (pos<expr.length())
2938 //printf("Prepending to rest!\n");
2939 char cs[2];cs[0]=c;cs[1]='\0';
2945 returnCharToStream(c);
2947 //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c);
2950 void addSearchDir(const char *dir)
2953 if (fi.isDir()) g_pathList->append(fi.absFilePath().utf8());
2956 void initPreprocessor()
2958 g_pathList = new QStrList;
2960 g_expandedDict = new DefineDict(17);
2963 void cleanUpPreprocessor()
2965 delete g_expandedDict; g_expandedDict=0;
2966 delete g_pathList; g_pathList=0;
2967 DefineManager::deleteInstance();
2971 void preprocessFile(const char *fileName,BufStr &input,BufStr &output)
2973 printlex(yy_flex_debug, TRUE, __FILE__, fileName);
2974 uint orgOffset=output.curPos();
2975 //printf("##########################\n%s\n####################\n",
2978 g_macroExpansion = Config_getBool("MACRO_EXPANSION");
2979 g_expandOnlyPredef = Config_getBool("EXPAND_ONLY_PREDEF");
2985 g_outputBuf=&output;
2986 g_includeStack.setAutoDelete(TRUE);
2987 g_includeStack.clear();
2988 g_expandedDict->setAutoDelete(FALSE);
2989 g_expandedDict->clear();
2990 g_condStack.clear();
2991 g_condStack.setAutoDelete(TRUE);
2992 //g_fileDefineDict->clear();
2994 setFileName(fileName);
2995 g_inputFileDef = g_yyFileDef;
2996 DefineManager::instance().startContext(g_yyFileName);
2998 static bool firstTime=TRUE;
3001 // add predefined macros
3003 QStrList &predefList = Config_getList("PREDEFINED");
3004 QStrListIterator sli(predefList);
3005 for (sli.toFirst();(defStr=sli.current());++sli)
3007 QCString ds = defStr;
3008 int i_equals=ds.find('=');
3009 int i_obrace=ds.find('(');
3010 int i_cbrace=ds.find(')');
3011 bool nonRecursive = i_equals>0 && ds.at(i_equals-1)==':';
3013 if (i_obrace==0) continue; // no define name
3015 if (i_obrace<i_equals && i_cbrace<i_equals &&
3016 i_obrace!=-1 && i_cbrace!=-1 &&
3018 ) // predefined function macro definition
3020 //printf("predefined function macro '%s'\n",defStr);
3021 QRegExp reId("[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*"); // regexp matching an id
3022 QDict<int> argDict(17);
3023 argDict.setAutoDelete(TRUE);
3024 int i=i_obrace+1,p,l,count=0;
3025 // gather the formal arguments in a dictionary
3026 while (i<i_cbrace && (p=reId.match(ds,i,&l)))
3028 if (l>0) // see bug375037
3030 argDict.insert(ds.mid(p,l),new int(count++));
3038 // strip definition part
3039 QCString tmp=ds.right(ds.length()-i_equals-1);
3040 QCString definition;
3042 // substitute all occurrences of formal arguments by their
3043 // corresponding markers
3044 while ((p=reId.match(tmp,i,&l))!=-1)
3046 if (p>i) definition+=tmp.mid(i,p-i);
3048 if ((argIndex=argDict[tmp.mid(p,l)])!=0)
3051 marker.sprintf(" @%d ",*argIndex);
3056 definition+=tmp.mid(p,l);
3060 if (i<(int)tmp.length()) definition+=tmp.mid(i,tmp.length()-i);
3062 // add define definition to the dictionary of defines for this file
3063 QCString dname = ds.left(i_obrace);
3064 if (!dname.isEmpty())
3066 Define *def = new Define;
3068 def->definition = definition;
3070 def->isPredefined = TRUE;
3071 def->nonRecursive = nonRecursive;
3072 def->fileDef = g_yyFileDef;
3073 def->fileName = fileName;
3074 DefineManager::instance().addDefine(g_yyFileName,def);
3077 //printf("#define `%s' `%s' #nargs=%d\n",
3078 // def->name.data(),def->definition.data(),def->nargs);
3080 else if ((i_obrace==-1 || i_obrace>i_equals) &&
3081 (i_cbrace==-1 || i_cbrace>i_equals) &&
3082 !ds.isEmpty() && (int)ds.length()>i_equals
3083 ) // predefined non-function macro definition
3085 //printf("predefined normal macro '%s'\n",defStr);
3086 Define *def = new Define;
3087 if (i_equals==-1) // simple define without argument
3090 def->definition = "1"; // substitute occurrences by 1 (true)
3092 else // simple define with argument
3094 int ine=i_equals - (nonRecursive ? 1 : 0);
3095 def->name = ds.left(ine);
3096 def->definition = ds.right(ds.length()-i_equals-1);
3098 if (!def->name.isEmpty())
3101 def->isPredefined = TRUE;
3102 def->nonRecursive = nonRecursive;
3103 def->fileDef = g_yyFileDef;
3104 def->fileName = fileName;
3105 DefineManager::instance().addDefine(g_yyFileName,def);
3112 //printf("#define `%s' `%s' #nargs=%d\n",
3113 // def->name.data(),def->definition.data(),def->nargs);
3126 g_expectGuard = guessSection(fileName)==Entry::HEADER_SEC;
3127 g_guardName.resize(0);
3128 g_lastGuardName.resize(0);
3129 g_guardExpr.resize(0);
3134 while (!g_condStack.isEmpty())
3136 CondCtx *ctx = g_condStack.pop();
3137 QCString sectionInfo = " ";
3138 if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label %s ",ctx->sectionId.data());
3139 warn(fileName,ctx->lineNr,"Conditional section%sdoes not have "
3140 "a corresponding \\endcond command within this file.",sectionInfo.data());
3142 // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829)
3143 forceEndCondSection();
3145 // remove locally defined macros so they can be redefined in another source file
3146 //if (g_fileDefineDict->count()>0)
3148 // QDictIterator<Define> di(*g_fileDefineDict);
3150 // for (di.toFirst();(d=di.current());++di)
3152 // g_globalDefineDict->remove(di.currentKey());
3154 // g_fileDefineDict->clear();
3157 if (Debug::isFlagSet(Debug::Preprocessor))
3159 char *orgPos=output.data()+orgOffset;
3160 char *newPos=output.data()+output.curPos();
3161 Debug::print(Debug::Preprocessor,0,"Preprocessor output (size: %d bytes):\n",newPos-orgPos);
3163 Debug::print(Debug::Preprocessor,0,"---------\n00001 ");
3164 while (orgPos<newPos)
3167 if (*orgPos=='\n') Debug::print(Debug::Preprocessor,0,"%05d ",++line);
3170 Debug::print(Debug::Preprocessor,0,"\n---------\n");
3171 if (DefineManager::instance().defineContext().count()>0)
3173 Debug::print(Debug::Preprocessor,0,"Macros accessible in this file:\n");
3174 Debug::print(Debug::Preprocessor,0,"---------\n");
3175 QDictIterator<Define> di(DefineManager::instance().defineContext());
3177 for (di.toFirst();(def=di.current());++di)
3179 Debug::print(Debug::Preprocessor,0,"%s ",def->name.data());
3181 Debug::print(Debug::Preprocessor,0,"\n---------\n");
3185 Debug::print(Debug::Preprocessor,0,"No macros accessible in this file.\n");
3188 DefineManager::instance().endContext();
3189 printlex(yy_flex_debug, FALSE, __FILE__, fileName);
3192 void preFreeScanner()
3194 #if defined(YY_FLEX_SUBMINOR_VERSION)
3202 #if !defined(YY_FLEX_SUBMINOR_VERSION)
3203 extern "C" { // some bogus code to keep the compiler happy
3204 // int preYYwrap() { return 1 ; }
3205 void preYYdummy() { yy_flex_realloc(0,0); }