1 /******************************************************************************
3 * Copyright (C) 1997-2020 by Dimitri van Heesch.
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
15 %option never-interactive
16 %option prefix="preYY"
18 %option extra-type="struct preYY_state *"
21 // forward declare yyscan_t to improve type safety
22 #define YY_TYPEDEF_YY_SCANNER_T
24 typedef yyguts_t *yyscan_t;
49 #include "containers.h"
60 #include "arguments.h"
62 #include "condparser.h"
68 #define YY_NO_UNISTD_H 1
70 #define USE_STATE2STRING 0
72 // Toggle for some debugging info
73 //#define DBG_CTX(x) fprintf x
74 #define DBG_CTX(x) do { } while(0)
77 static const char *stateToString(int state);
82 preYY_CondCtx(int line,QCString id,bool b)
83 : lineNr(line),sectionId(id), skip(b) {}
91 FileState(uint size) : fileBuf(size) {}
95 BufStr *oldFileBuf = 0;
96 yy_size_t oldFileBufPos = 0;
97 YY_BUFFER_STATE bufState = 0;
101 struct PreIncludeInfo
103 PreIncludeInfo(const QCString &fn,FileDef *srcFd, FileDef *dstFd,const QCString &iName,bool loc, bool imp)
104 : fileName(fn), fromFileDef(srcFd), toFileDef(dstFd), includeName(iName), local(loc), imported(imp)
107 QCString fileName; // file name in which the include statement was found
108 FileDef *fromFileDef; // filedef in which the include statement was found
109 FileDef *toFileDef; // filedef to which the include is pointing
110 QCString includeName; // name used in the #include statement
111 bool local; // is it a "local" or <global> include
112 bool imported; // include via "import" keyword (Objective-C)
115 /** A dictionary of managed Define objects. */
116 typedef std::map< std::string, Define > DefineMap;
118 /** @brief Class that manages the defines available while
119 * preprocessing files.
124 /** Local class used to hold the defines for a single file */
128 /** Creates an empty container for defines */
129 DefinesPerFile(DefineManager *parent)
133 void addInclude(std::string fileName)
135 m_includedFiles.insert(fileName);
137 void store(const DefineMap &fromMap)
139 for (auto &kv : fromMap)
141 m_defines.emplace(kv.first,kv.second);
143 //printf(" m_defines.size()=%zu\n",m_defines.size());
146 void retrieve(DefineMap &toMap)
148 StringSet includeStack;
149 retrieveRec(toMap,includeStack);
151 void retrieveRec(DefineMap &toMap,StringSet &includeStack)
153 //printf(" retrieveRec #includedFiles=%zu\n",m_includedFiles.size());
154 for (auto incFile : m_includedFiles)
156 DefinesPerFile *dpf = m_parent->find(incFile);
157 if (dpf && includeStack.find(incFile)==includeStack.end())
159 includeStack.insert(incFile);
160 dpf->retrieveRec(toMap,includeStack);
161 //printf(" retrieveRec: processing include %s: #toMap=%zu\n",qPrint(incFile),toMap.size());
164 for (auto &kv : m_defines)
166 toMap.emplace(kv.first,kv.second);
169 bool stored() const { return m_stored; }
171 DefineManager *m_parent;
173 StringSet m_includedFiles;
174 bool m_stored = false;
177 friend class DefinesPerFile;
180 void addInclude(std::string fromFileName,std::string toFileName)
182 //printf("DefineManager::addInclude('%s'->'%s')\n",fromFileName.c_str(),toFileName.c_str());
183 auto it = m_fileMap.find(fromFileName);
184 if (it==m_fileMap.end())
186 it = m_fileMap.emplace(fromFileName,std::make_unique<DefinesPerFile>(this)).first;
188 auto &dpf = it->second;
189 dpf->addInclude(toFileName);
192 void store(std::string fileName,const DefineMap &fromMap)
194 //printf("DefineManager::store(%s,#=%zu)\n",fileName.c_str(),fromMap.size());
195 auto it = m_fileMap.find(fileName);
196 if (it==m_fileMap.end())
198 it = m_fileMap.emplace(fileName,std::make_unique<DefinesPerFile>(this)).first;
200 it->second->store(fromMap);
203 void retrieve(std::string fileName,DefineMap &toMap)
205 auto it = m_fileMap.find(fileName);
206 if (it!=m_fileMap.end())
208 auto &dpf = it->second;
209 dpf->retrieve(toMap);
211 //printf("DefineManager::retrieve(%s,#=%zu)\n",fileName.c_str(),toMap.size());
214 bool alreadyProcessed(std::string fileName) const
216 auto it = m_fileMap.find(fileName);
217 if (it!=m_fileMap.end())
219 return it->second->stored();
225 /** Helper function to return the DefinesPerFile object for a given file name. */
226 DefinesPerFile *find(std::string fileName) const
228 auto it = m_fileMap.find(fileName);
229 return it!=m_fileMap.end() ? it->second.get() : nullptr;
232 std::unordered_map< std::string, std::unique_ptr<DefinesPerFile> > m_fileMap;
236 /* -----------------------------------------------------------------
240 static std::mutex g_debugMutex;
241 static std::mutex g_globalDefineMutex;
242 static std::mutex g_updateGlobals;
243 static DefineManager g_defineManager;
246 /* -----------------------------------------------------------------
257 FileDef *yyFileDef = 0;
258 FileDef *inputFileDef = 0;
265 QCString defExtraSpacing;
266 bool defContinue = false;
267 bool defVarArgs = false;
268 int lastCContext = 0;
269 int lastCPPContext = 0;
270 BufStr *inputBuf = 0;
271 yy_size_t inputBufPos = 0;
272 BufStr *outputBuf = 0;
274 bool quoteArg = false;
275 bool idStart = false;
276 int findDefArgContext = 0;
277 bool expectGuard = false;
279 QCString lastGuardName;
283 bool nospaces = false; // add extra spaces during macro expansion
286 bool macroExpansion = false; // from the configuration
287 bool expandOnlyPredef = false; // from the configuration
288 QCString potentialDefine;
289 int commentCount = 0;
290 bool insideComment = false;
291 bool isImported = false;
295 bool insideCS = false; // C# has simpler preprocessor
296 bool insideFtn = false;
297 bool isSource = false;
299 yy_size_t fenceSize = 0;
300 bool ccomment = false;
302 bool isSpecialComment = false;
303 StringVector pathList;
305 BoolStack levelGuard;
306 std::stack< std::unique_ptr<preYY_CondCtx> > condStack;
307 std::deque< std::unique_ptr<FileState> > includeStack;
308 std::unordered_map<std::string,Define*> expandedDict;
309 StringUnorderedSet expanded;
310 ConstExpressionParser constExpParser;
311 DefineMap contextDefines; // macros imported from other files
312 DefineMap localDefines; // macros defined in this file
313 DefineList macroDefinitions;
314 LinkedMap<PreIncludeInfo> includeRelations;
317 // stateless functions
318 static QCString escapeAt(const QCString &text);
319 static QCString extractTrailingComment(const QCString &s);
320 static char resolveTrigraph(char c);
322 // stateful functions
323 static inline void outputArray(yyscan_t yyscanner,const char *a,yy_size_t len);
324 static inline void outputString(yyscan_t yyscanner,const QCString &s);
325 static inline void outputChar(yyscan_t yyscanner,char c);
326 static inline void outputSpaces(yyscan_t yyscanner,char *s);
327 static inline void outputSpace(yyscan_t yyscanner,char c);
328 static inline void extraSpacing(yyscan_t yyscanner);
329 static QCString expandMacro(yyscan_t yyscanner,const QCString &name);
330 static void readIncludeFile(yyscan_t yyscanner,const QCString &inc);
331 static void incrLevel(yyscan_t yyscanner);
332 static void decrLevel(yyscan_t yyscanner);
333 static void setCaseDone(yyscan_t yyscanner,bool value);
334 static bool otherCaseDone(yyscan_t yyscanner);
335 static bool computeExpression(yyscan_t yyscanner,const QCString &expr);
336 static void startCondSection(yyscan_t yyscanner,const QCString §Id);
337 static void endCondSection(yyscan_t yyscanner);
338 static void addMacroDefinition(yyscan_t yyscanner);
339 static void addDefine(yyscan_t yyscanner);
340 static void setFileName(yyscan_t yyscanner,const QCString &name);
341 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
342 static Define * isDefined(yyscan_t yyscanner,const QCString &name);
344 /* ----------------------------------------------------------------- */
347 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
349 /* ----------------------------------------------------------------- */
353 IDSTART [a-z_A-Z\x80-\xFF]
354 ID {IDSTART}[a-z_A-Z0-9\x80-\xFF]*
358 RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
359 RAWEND ")"[^ \t\(\)\\]{0,16}\"
360 CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
368 // optional characters after import
369 ENDIMPORTopt [^\\\n]*
370 // Optional white space
385 %x CopyStringFtnDouble
399 %x JavaDocVerbatimCode
420 <*>"??"[=/'()!<>-] { // Trigraph
421 unput(resolveTrigraph(yytext[2]));
424 yyextra->yyColNr+=(int)yyleng;
426 yyextra->potentialDefine=yytext;
429 <Start>^("%top{"|"%{") {
430 if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_Lex) REJECT
431 outputArray(yyscanner,yytext,yyleng);
434 <Start>^{Bopt}/[^#] {
435 outputArray(yyscanner,yytext,yyleng);
438 <Start>^{B}*[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]+{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors?
440 for (i=(int)yyleng-1;i>=0;i--)
446 <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
447 <Start>^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\)\n]*")"{B}*\n { // function like macro
448 bool skipFuncMacros = Config_getBool(SKIP_FUNCTION_MACROS);
449 QCString name(yytext);
450 int pos = name.find('(');
451 if (pos<0) pos=0; // should never happen
452 name=name.left(pos).stripWhiteSpace();
455 if (skipFuncMacros && !yyextra->insideFtn &&
456 name!="Q_PROPERTY" &&
458 (yyextra->includeStack.empty() || yyextra->curlyCount>0) &&
459 yyextra->macroExpansion &&
460 (def=isDefined(yyscanner,name)) &&
461 /*macroIsAccessible(def) &&*/
462 (!yyextra->expandOnlyPredef || def->isPredefined)
466 outputChar(yyscanner,'\n');
472 for (i=(int)yyleng-1;i>=0;i--)
479 <CopyLine,LexCopyLine>"extern"{BN}*"\""[^\"]+"\""{BN}*("{")? {
480 QCString text=yytext;
481 yyextra->yyLineNr+=text.contains('\n');
482 outputArray(yyscanner,yytext,yyleng);
484 <CopyLine,LexCopyLine>{RAWBEGIN} {
485 yyextra->delimiter = yytext+2;
486 yyextra->delimiter=yyextra->delimiter.left(yyextra->delimiter.length()-1);
487 outputArray(yyscanner,yytext,yyleng);
488 BEGIN(CopyRawString);
490 <CopyLine,LexCopyLine>"{" { // count brackets inside the main file
491 if (yyextra->includeStack.empty())
493 yyextra->curlyCount++;
495 outputChar(yyscanner,*yytext);
498 outputArray(yyscanner,yytext,yyleng);
500 <CopyLine,LexCopyLine>"}" { // count brackets inside the main file
501 if (yyextra->includeStack.empty() && yyextra->curlyCount>0)
503 yyextra->curlyCount--;
505 outputChar(yyscanner,*yytext);
507 <CopyLine,LexCopyLine>"'"\\[0-7]{1,3}"'" {
508 outputArray(yyscanner,yytext,yyleng);
510 <CopyLine,LexCopyLine>"'"\\."'" {
511 outputArray(yyscanner,yytext,yyleng);
513 <CopyLine,LexCopyLine>"'"."'" {
514 outputArray(yyscanner,yytext,yyleng);
516 <CopyLine,LexCopyLine>@\" {
517 if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_CSharp) REJECT;
518 outputArray(yyscanner,yytext,yyleng);
519 BEGIN( CopyStringCs );
521 <CopyLine,LexCopyLine>\" {
522 outputChar(yyscanner,*yytext);
523 if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_Fortran)
529 BEGIN( CopyStringFtnDouble );
532 <CopyLine,LexCopyLine>\' {
533 if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_Fortran) REJECT;
534 outputChar(yyscanner,*yytext);
535 BEGIN( CopyStringFtn );
537 <CopyString>[^\"\\\r\n]+ {
538 outputArray(yyscanner,yytext,yyleng);
540 <CopyStringCs>[^\"\r\n]+ {
541 outputArray(yyscanner,yytext,yyleng);
544 outputArray(yyscanner,yytext,yyleng);
546 <CopyString,CopyStringCs>\" {
547 outputChar(yyscanner,*yytext);
550 <CopyStringFtnDouble>[^\"\\\r\n]+ {
551 outputArray(yyscanner,yytext,yyleng);
553 <CopyStringFtnDouble>\\. {
554 outputArray(yyscanner,yytext,yyleng);
556 <CopyStringFtnDouble>\" {
557 outputChar(yyscanner,*yytext);
560 <CopyStringFtn>[^\'\\\r\n]+ {
561 outputArray(yyscanner,yytext,yyleng);
564 outputArray(yyscanner,yytext,yyleng);
567 outputChar(yyscanner,*yytext);
570 <CopyRawString>{RAWEND} {
571 outputArray(yyscanner,yytext,yyleng);
572 QCString delimiter = yytext+1;
573 delimiter=delimiter.left(delimiter.length()-1);
574 if (delimiter==yyextra->delimiter)
579 <CopyRawString>[^)]+ {
580 outputArray(yyscanner,yytext,yyleng);
583 outputChar(yyscanner,*yytext);
585 <CopyLine,LexCopyLine>{ID}/{BN}{0,80}"(" {
586 yyextra->expectGuard = FALSE;
588 //def=yyextra->globalDefineDict->find(yytext);
589 //def=isDefined(yyscanner,yytext);
590 //printf("Search for define %s found=%d yyextra->includeStack.empty()=%d "
591 // "yyextra->curlyCount=%d yyextra->macroExpansion=%d yyextra->expandOnlyPredef=%d "
592 // "isPreDefined=%d\n",yytext,def ? 1 : 0,
593 // yyextra->includeStack.empty(),yyextra->curlyCount,yyextra->macroExpansion,yyextra->expandOnlyPredef,
594 // def ? def->isPredefined : -1
596 if ((yyextra->includeStack.empty() || yyextra->curlyCount>0) &&
597 yyextra->macroExpansion &&
598 (def=isDefined(yyscanner,yytext)) &&
599 /*(def->isPredefined || macroIsAccessible(def)) && */
600 (!yyextra->expandOnlyPredef || def->isPredefined)
603 //printf("Found it! #args=%d\n",def->nargs);
604 yyextra->roundCount=0;
605 yyextra->defArgsStr=yytext;
606 if (def->nargs==-1) // no function macro
608 QCString result = def->isPredefined ? def->definition : expandMacro(yyscanner,yyextra->defArgsStr);
609 outputString(yyscanner,result);
611 else // zero or more arguments
613 yyextra->findDefArgContext = CopyLine;
614 BEGIN(FindDefineArgs);
619 outputArray(yyscanner,yytext,yyleng);
622 <CopyLine,LexCopyLine>{ID} {
624 if ((yyextra->includeStack.empty() || yyextra->curlyCount>0) &&
625 yyextra->macroExpansion &&
626 (def=isDefined(yyscanner,yytext)) &&
628 /*(def->isPredefined || macroIsAccessible(def)) &&*/
629 (!yyextra->expandOnlyPredef || def->isPredefined)
632 QCString result=def->isPredefined ? def->definition : expandMacro(yyscanner,yytext);
633 outputString(yyscanner,result);
637 outputArray(yyscanner,yytext,yyleng);
640 <CopyLine,LexCopyLine>"\\"\r?/\n { // strip line continuation characters
641 if (getLanguageFromFileName(yyextra->yyFileName)==SrcLangExt_Fortran) outputChar(yyscanner,*yytext);
643 <CopyLine,LexCopyLine>\\. {
644 outputArray(yyscanner,yytext,(int)yyleng);
646 <CopyLine,LexCopyLine>. {
647 outputChar(yyscanner,*yytext);
649 <CopyLine,LexCopyLine>\n {
650 outputChar(yyscanner,'\n');
655 <FindDefineArgs>"(" {
656 yyextra->defArgsStr+='(';
657 yyextra->roundCount++;
659 <FindDefineArgs>")" {
660 yyextra->defArgsStr+=')';
661 yyextra->roundCount--;
662 if (yyextra->roundCount==0)
664 QCString result=expandMacro(yyscanner,yyextra->defArgsStr);
665 //printf("yyextra->defArgsStr='%s'->'%s'\n",qPrint(yyextra->defArgsStr),qPrint(result));
666 if (yyextra->findDefArgContext==CopyLine)
668 outputString(yyscanner,result);
669 BEGIN(yyextra->findDefArgContext);
671 else // yyextra->findDefArgContext==IncludeID
673 readIncludeFile(yyscanner,result);
674 yyextra->nospaces=FALSE;
680 <FindDefineArgs>")"{B}*"(" {
681 yyextra->defArgsStr+=yytext;
684 <FindDefineArgs>{CHARLIT} {
685 yyextra->defArgsStr+=yytext;
687 <FindDefineArgs>{CCS}[*]? {
688 yyextra->defArgsStr+=yytext;
689 BEGIN(ArgCopyCComment);
692 yyextra->defArgsStr+=*yytext;
696 if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_Fortran) REJECT;
697 yyextra->defArgsStr+=*yytext;
701 yyextra->defArgsStr+=' ';
703 outputChar(yyscanner,'\n');
705 <FindDefineArgs>"@" {
706 yyextra->defArgsStr+="@@";
709 yyextra->defArgsStr+=*yytext;
711 <ArgCopyCComment>[^*\n]+ {
712 yyextra->defArgsStr+=yytext;
714 <ArgCopyCComment>{CCE} {
715 yyextra->defArgsStr+=yytext;
716 BEGIN(FindDefineArgs);
718 <ArgCopyCComment>\n {
719 yyextra->defArgsStr+=' ';
721 outputChar(yyscanner,'\n');
724 yyextra->defArgsStr+=yytext;
727 yyextra->defArgsStr+=*yytext;
728 BEGIN(FindDefineArgs);
731 if (getLanguageFromFileName(yyextra->yyFileName)!=SrcLangExt_Fortran) REJECT;
732 yyextra->defArgsStr+=*yytext;
733 BEGIN(FindDefineArgs);
736 <ReadString>{CPPC}|{CCS} {
737 yyextra->defArgsStr+=yytext;
739 <ReadString>\\/\r?\n { // line continuation
742 yyextra->defArgsStr+=yytext;
745 yyextra->defArgsStr+=*yytext;
747 <Command>("include"|"import"){B}+/{ID} {
748 yyextra->isImported = yytext[1]=='m';
749 if (yyextra->macroExpansion)
752 <Command>("include"|"import"){B}*[<"] {
753 yyextra->isImported = yytext[1]=='m';
755 c[0]=yytext[yyleng-1];c[1]='\0';
759 <Command>("cmake")?"define"{B}+ {
760 yyextra->potentialDefine += substitute(yytext,"cmake"," ");
761 //printf("!!!DefName\n");
762 yyextra->yyColNr+=(int)yyleng;
765 <Command>"ifdef"/{B}*"(" {
766 incrLevel(yyscanner);
767 yyextra->guardExpr.resize(0);
770 <Command>"ifdef"/{B}+ {
771 //printf("Pre.l: ifdef\n");
772 incrLevel(yyscanner);
773 yyextra->guardExpr.resize(0);
776 <Command>"ifndef"/{B}*"(" {
777 incrLevel(yyscanner);
778 yyextra->guardExpr="! ";
781 <Command>"ifndef"/{B}+ {
782 incrLevel(yyscanner);
783 yyextra->guardExpr="! ";
786 <Command>"if"/[ \t(!] {
787 incrLevel(yyscanner);
788 yyextra->guardExpr.resize(0);
791 <Command>("elif"|"else"{B}*"if")/[ \t(!] {
792 if (!otherCaseDone(yyscanner))
794 yyextra->guardExpr.resize(0);
803 <Command>"else"/[^a-z_A-Z0-9\x80-\xFF] {
804 if (otherCaseDone(yyscanner))
811 setCaseDone(yyscanner,TRUE);
814 <Command>"undef"{B}+ {
817 <Command>("elif"|"else"{B}*"if")/[ \t(!] {
818 if (!otherCaseDone(yyscanner))
820 yyextra->guardExpr.resize(0);
824 <Command>"endif"/[^a-z_A-Z0-9\x80-\xFF] {
825 //printf("Pre.l: #endif\n");
826 decrLevel(yyscanner);
828 <Command,IgnoreLine>\n {
829 outputChar(yyscanner,'\n');
833 <Command>"pragma"{B}+"once" {
834 yyextra->expectGuard = FALSE;
836 <Command>{ID} { // unknown directive
839 <IgnoreLine>\\[\r]?\n {
840 outputChar(yyscanner,'\n');
844 <Command>. { yyextra->potentialDefine += yytext[0]=='\t' ? '\t' : ' ';
845 yyextra->yyColNr+=(int)yyleng;
849 if ((def=isDefined(yyscanner,yytext))
850 /*&& !def->isPredefined*/
851 && !def->nonRecursive
854 //printf("undefining %s\n",yytext);
860 outputChar(yyscanner,'\n');
861 yyextra->guardExpr+=' ';
864 <Guard>"defined"/{B}*"(" {
867 <Guard>"defined"/{B}+ {
870 <Guard>{ID} { yyextra->guardExpr+=yytext; }
871 <Guard>"@" { yyextra->guardExpr+="@@"; }
872 <Guard>. { yyextra->guardExpr+=*yytext; }
875 //printf("Guard: '%s'\n",
876 // qPrint(yyextra->guardExpr));
877 bool guard=computeExpression(yyscanner,yyextra->guardExpr);
878 setCaseDone(yyscanner,guard);
889 <DefinedExpr1,DefinedExpr2>\\\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
891 if (isDefined(yyscanner,yytext) || yyextra->guardName==yytext)
892 yyextra->guardExpr+=" 1L ";
894 yyextra->guardExpr+=" 0L ";
895 yyextra->lastGuardName=yytext;
899 if (isDefined(yyscanner,yytext) || yyextra->guardName==yytext)
900 yyextra->guardExpr+=" 1L ";
902 yyextra->guardExpr+=" 0L ";
903 yyextra->lastGuardName=yytext;
905 <DefinedExpr1,DefinedExpr2>\n { // should not happen, handle anyway
913 <DefinedExpr1,DefinedExpr2>.
914 <SkipCPPBlock>^{B}*"#" { BEGIN(SkipCommand); }
915 <SkipCPPBlock>^{Bopt}/[^#] { BEGIN(SkipLine); }
916 <SkipCPPBlock>\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
918 <SkipCommand>"if"(("n")?("def"))?/[ \t(!] {
919 incrLevel(yyscanner);
921 //printf("#if... depth=%d\n",yyextra->ifcount);
923 <SkipCommand>"else" {
924 //printf("Else! yyextra->ifcount=%d otherCaseDone=%d\n",yyextra->ifcount,otherCaseDone());
925 if (yyextra->ifcount==0 && !otherCaseDone(yyscanner))
927 setCaseDone(yyscanner,TRUE);
928 //outputChar(yyscanner,'\n');
932 <SkipCommand>("elif"|"else"{B}*"if")/[ \t(!] {
933 if (yyextra->ifcount==0)
935 if (!otherCaseDone(yyscanner))
937 yyextra->guardExpr.resize(0);
938 yyextra->lastGuardName.resize(0);
947 <SkipCommand>"endif" {
948 yyextra->expectGuard = FALSE;
949 decrLevel(yyscanner);
950 if (--yyextra->ifcount<0)
952 //outputChar(yyscanner,'\n');
957 outputChar(yyscanner,'\n');
961 <SkipCommand>{ID} { // unknown directive
966 <SkipLine>{CHARLIT} { }
971 <SkipString>{CPPC}/[^\n]* {
973 <SkipLine,SkipCommand,SkipCPPBlock>{CPPC}[^\n]* {
974 yyextra->lastCPPContext=YY_START;
975 BEGIN(RemoveCPPComment);
977 <SkipString>{CCS}/[^\n]* {
979 <SkipLine,SkipCommand,SkipCPPBlock>{CCS}/[^\n]* {
980 yyextra->lastCContext=YY_START;
981 BEGIN(RemoveCComment);
984 outputChar(yyscanner,'\n');
988 <SkipString>[^"\\\n]+ { }
994 <IncludeID>{ID}{Bopt}/"(" {
995 yyextra->nospaces=TRUE;
996 yyextra->roundCount=0;
997 yyextra->defArgsStr=yytext;
998 yyextra->findDefArgContext = IncludeID;
999 BEGIN(FindDefineArgs);
1002 yyextra->nospaces=TRUE;
1003 readIncludeFile(yyscanner,expandMacro(yyscanner,yytext));
1006 <Include>[^\">\n]+[\">] {
1007 yyextra->incName+=yytext;
1008 readIncludeFile(yyscanner,yyextra->incName);
1009 if (yyextra->isImported)
1018 <EndImport>{ENDIMPORTopt}/\n {
1021 <EndImport>\\[\r]?"\n" {
1022 outputChar(yyscanner,'\n');
1023 yyextra->yyLineNr++;
1027 <DefName>{ID}/("\\\n")*"(" { // define with argument
1028 //printf("Define() '%s'\n",yytext);
1029 yyextra->argMap.clear();
1030 yyextra->defArgs = 0;
1031 yyextra->defArgsStr.resize(0);
1032 yyextra->defText.resize(0);
1033 yyextra->defLitText.resize(0);
1034 yyextra->defName = yytext;
1035 yyextra->defVarArgs = FALSE;
1036 yyextra->defExtraSpacing.resize(0);
1037 yyextra->defContinue = false;
1040 <DefName>{ID}{B}+"1"/[ \r\t\n] { // special case: define with 1 -> can be "guard"
1041 //printf("Define '%s'\n",yytext);
1042 yyextra->argMap.clear();
1043 yyextra->defArgs = -1;
1044 yyextra->defArgsStr.resize(0);
1045 yyextra->defName = QCString(yytext).left(yyleng-1).stripWhiteSpace();
1046 yyextra->defVarArgs = FALSE;
1047 //printf("Guard check: %s!=%s || %d\n",
1048 // qPrint(yyextra->defName),qPrint(yyextra->lastGuardName),yyextra->expectGuard);
1049 if (yyextra->curlyCount>0 || yyextra->defName!=yyextra->lastGuardName || !yyextra->expectGuard)
1050 { // define may appear in the output
1051 QCString def = yyextra->potentialDefine +
1053 outputString(yyscanner,def);
1054 outputSpaces(yyscanner,yytext+yyextra->defName.length());
1055 yyextra->quoteArg=FALSE;
1056 yyextra->insideComment=FALSE;
1057 yyextra->lastGuardName.resize(0);
1058 yyextra->defText="1";
1059 yyextra->defLitText="1";
1062 else // define is a guard => hide
1064 //printf("Found a guard %s\n",yytext);
1065 yyextra->defText.resize(0);
1066 yyextra->defLitText.resize(0);
1069 yyextra->expectGuard=FALSE;
1071 <DefName>{ID}/{B}*"\n" { // empty define
1072 yyextra->argMap.clear();
1073 yyextra->defArgs = -1;
1074 yyextra->defName = yytext;
1075 yyextra->defArgsStr.resize(0);
1076 yyextra->defText.resize(0);
1077 yyextra->defLitText.resize(0);
1078 yyextra->defVarArgs = FALSE;
1079 //printf("Guard check: %s!=%s || %d\n",
1080 // qPrint(yyextra->defName),qPrint(yyextra->lastGuardName),yyextra->expectGuard);
1081 if (yyextra->curlyCount>0 || yyextra->defName!=yyextra->lastGuardName || !yyextra->expectGuard)
1082 { // define may appear in the output
1083 QCString def = yyextra->potentialDefine + yyextra->defName;
1084 outputString(yyscanner,def);
1085 yyextra->quoteArg=FALSE;
1086 yyextra->insideComment=FALSE;
1087 if (yyextra->insideCS) yyextra->defText="1"; // for C#, use "1" as define text
1090 else // define is a guard => hide
1092 //printf("Found a guard %s\n",yytext);
1093 yyextra->guardName = yytext;
1094 yyextra->lastGuardName.resize(0);
1097 yyextra->expectGuard=FALSE;
1099 <DefName>{ID}/{B}* { // define with content
1100 //printf("Define '%s'\n",yytext);
1101 yyextra->argMap.clear();
1102 yyextra->defArgs = -1;
1103 yyextra->defArgsStr.resize(0);
1104 yyextra->defText.resize(0);
1105 yyextra->defLitText.resize(0);
1106 yyextra->defName = yytext;
1107 yyextra->defVarArgs = FALSE;
1108 QCString def = yyextra->potentialDefine +
1110 yyextra->defArgsStr ;
1111 outputString(yyscanner,def);
1112 yyextra->quoteArg=FALSE;
1113 yyextra->insideComment=FALSE;
1117 yyextra->defExtraSpacing+="\n";
1118 yyextra->defContinue = true;
1119 yyextra->yyLineNr++;
1121 <DefineArg>{B}* { yyextra->defExtraSpacing+=yytext; }
1122 <DefineArg>","{B}* { yyextra->defArgsStr+=yytext; }
1123 <DefineArg>"("{B}* { yyextra->defArgsStr+=yytext; }
1124 <DefineArg>{B}*")"{B}* {
1125 extraSpacing(yyscanner);
1126 yyextra->defArgsStr+=yytext;
1127 QCString def = yyextra->potentialDefine +
1129 yyextra->defArgsStr +
1130 yyextra->defExtraSpacing ;
1131 outputString(yyscanner,def);
1132 yyextra->quoteArg=FALSE;
1133 yyextra->insideComment=FALSE;
1136 <DefineArg>"..." { // Variadic macro
1137 yyextra->defVarArgs = TRUE;
1138 yyextra->defArgsStr+=yytext;
1139 yyextra->argMap.emplace(std::string("__VA_ARGS__"),yyextra->defArgs);
1142 <DefineArg>{ID}{B}*("..."?) {
1143 //printf("Define addArg(%s)\n",yytext);
1144 QCString argName=yytext;
1145 yyextra->defVarArgs = yytext[yyleng-1]=='.';
1146 if (yyextra->defVarArgs) // strip ellipsis
1148 argName=argName.left(argName.length()-3);
1150 argName = argName.stripWhiteSpace();
1151 yyextra->defArgsStr+=yytext;
1152 yyextra->argMap.emplace(toStdString(argName),yyextra->defArgs);
1154 extraSpacing(yyscanner);
1157 <DefineText>"/ **"|"/ *!" {
1158 yyextra->defText+=yytext;
1159 yyextra->defLitText+=yytext;
1160 yyextra->insideComment=TRUE;
1163 yyextra->defText+=yytext;
1164 yyextra->defLitText+=yytext;
1165 yyextra->insideComment=FALSE;
1168 <DefineText>{CCS}[!*]? {
1169 yyextra->defText+=yytext;
1170 yyextra->defLitText+=yytext;
1171 yyextra->lastCContext=YY_START;
1172 yyextra->commentCount=1;
1173 BEGIN(CopyCComment);
1175 <DefineText>{CPPC}[!/]? {
1176 outputArray(yyscanner,yytext,yyleng);
1177 yyextra->lastCPPContext=YY_START;
1178 yyextra->defLitText+=' ';
1179 BEGIN(SkipCPPComment);
1181 <SkipCComment>[/]?{CCE} {
1182 if (yytext[0]=='/') outputChar(yyscanner,'/');
1183 outputChar(yyscanner,'*');outputChar(yyscanner,'/');
1184 if (--yyextra->commentCount<=0)
1186 if (yyextra->lastCContext==Start)
1187 // small hack to make sure that ^... rule will
1188 // match when going to Start... Example: "/*...*/ some stuff..."
1190 YY_CURRENT_BUFFER->yy_at_bol=1;
1192 BEGIN(yyextra->lastCContext);
1195 <SkipCComment>{CPPC}("/")* {
1196 outputArray(yyscanner,yytext,yyleng);
1198 <SkipCComment>{CCS} {
1199 outputChar(yyscanner,'/');outputChar(yyscanner,'*');
1200 //yyextra->commentCount++;
1202 <SkipCComment>[\\@][\\@]("f{"|"f$"|"f[""f(") {
1203 outputArray(yyscanner,yytext,yyleng);
1205 <SkipCComment>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
1206 bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1207 if (!markdownSupport || !yyextra->isSpecialComment)
1213 outputArray(yyscanner,yytext,yyleng);
1214 yyextra->fenceSize=(int)yyleng;
1215 BEGIN(SkipVerbatim);
1218 <SkipCComment>^({B}*"*"+)?{B}{0,3}"```"[`]* {
1219 bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1220 if (!markdownSupport || !yyextra->isSpecialComment)
1226 outputArray(yyscanner,yytext,yyleng);
1227 yyextra->fenceSize=(int)yyleng;
1228 BEGIN(SkipVerbatim);
1231 <SkipCComment>[\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ {
1232 outputArray(yyscanner,yytext,yyleng);
1233 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1235 <SkipCComment>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ {
1236 outputArray(yyscanner,yytext,yyleng);
1237 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1238 yyextra->fenceSize=0;
1241 yyextra->blockName="f";
1245 QCString bn=&yytext[1];
1246 int i = bn.find('{'); // for \code{.c}
1247 if (i!=-1) bn=bn.left(i);
1248 yyextra->blockName=bn.stripWhiteSpace();
1250 BEGIN(SkipVerbatim);
1252 <SkipCComment>"{"[ \t]*"@code"/[ \t\n] {
1253 outputArray(yyscanner,"@code",5);
1254 yyextra->javaBlock=1;
1255 BEGIN(JavaDocVerbatimCode);
1257 <SkipCComment,SkipCPPComment>[\\@][\\@]"cond"[ \t]+ { // escaped @cond
1258 outputArray(yyscanner,yytext,yyleng);
1260 <SkipCPPComment>[\\@]"cond"[ \t]+ { // conditional section
1261 yyextra->ccomment=TRUE;
1262 yyextra->condCtx=YY_START;
1265 <SkipCComment>[\\@]"cond"[ \t]+ { // conditional section
1266 yyextra->ccomment=FALSE;
1267 yyextra->condCtx=YY_START;
1270 <CondLineC,CondLineCpp>[!()&| \ta-z_A-Z0-9\x80-\xFF.\-]+ {
1271 startCondSection(yyscanner,yytext);
1274 if (YY_START==CondLineC)
1277 outputArray(yyscanner,"*/",2);
1278 yyextra->ccomment=TRUE;
1282 yyextra->ccomment=FALSE;
1288 BEGIN(yyextra->condCtx);
1291 <CondLineC,CondLineCpp>. { // non-guard character
1293 startCondSection(yyscanner," ");
1296 if (YY_START==CondLineC)
1299 outputArray(yyscanner,"*/",2);
1300 yyextra->ccomment=TRUE;
1304 yyextra->ccomment=FALSE;
1310 BEGIN(yyextra->condCtx);
1313 <SkipCComment,SkipCPPComment>[\\@]"cond"{WSopt}/\n { // no guard
1314 if (YY_START==SkipCComment)
1316 yyextra->ccomment=TRUE;
1318 outputArray(yyscanner,"*/",2);
1322 yyextra->ccomment=FALSE;
1324 yyextra->condCtx=YY_START;
1325 startCondSection(yyscanner," ");
1328 <SkipCond>\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
1330 <SkipCond>[^\/\!*\\@\n]+ { }
1331 <SkipCond>{CPPC}[/!] { yyextra->ccomment=FALSE; }
1332 <SkipCond>{CCS}[*!] { yyextra->ccomment=TRUE; }
1333 <SkipCond,SkipCComment,SkipCPPComment>[\\@][\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1336 outputArray(yyscanner,yytext,yyleng);
1339 <SkipCond>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1340 bool oldSkip = yyextra->skip;
1341 endCondSection(yyscanner);
1342 if (oldSkip && !yyextra->skip)
1344 if (yyextra->ccomment)
1346 outputArray(yyscanner,"/** ",4);
1348 BEGIN(yyextra->condCtx);
1351 <SkipCComment,SkipCPPComment>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1352 bool oldSkip = yyextra->skip;
1353 endCondSection(yyscanner);
1354 if (oldSkip && !yyextra->skip)
1356 BEGIN(yyextra->condCtx);
1359 <SkipVerbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}""f}") { /* end of verbatim block */
1360 outputArray(yyscanner,yytext,yyleng);
1361 if (yytext[1]=='f' && yyextra->blockName=="f")
1363 BEGIN(SkipCComment);
1365 else if (&yytext[4]==yyextra->blockName)
1367 BEGIN(SkipCComment);
1370 <SkipVerbatim>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
1371 outputArray(yyscanner,yytext,yyleng);
1372 if (yyextra->fenceSize==(yy_size_t)yyleng)
1374 BEGIN(SkipCComment);
1377 <SkipVerbatim>^({B}*"*"+)?{B}{0,3}"```"[`]* {
1378 outputArray(yyscanner,yytext,yyleng);
1379 if (yyextra->fenceSize==(yy_size_t)yyleng)
1381 BEGIN(SkipCComment);
1384 <SkipVerbatim>{CCE}|{CCS} {
1385 outputArray(yyscanner,yytext,yyleng);
1387 <JavaDocVerbatimCode>"{" {
1388 if (yyextra->javaBlock==0)
1394 yyextra->javaBlock++;
1395 outputArray(yyscanner,yytext,(int)yyleng);
1398 <JavaDocVerbatimCode>"}" {
1399 if (yyextra->javaBlock==0)
1405 yyextra->javaBlock--;
1406 if (yyextra->javaBlock==0)
1408 outputArray(yyscanner," @endcode ",10);
1409 BEGIN(SkipCComment);
1413 outputArray(yyscanner,yytext,(int)yyleng);
1417 <JavaDocVerbatimCode>\n { /* new line in verbatim block */
1418 outputArray(yyscanner,yytext,(int)yyleng);
1420 <JavaDocVerbatimCode>. { /* any other character */
1421 outputArray(yyscanner,yytext,(int)yyleng);
1423 <SkipCComment,SkipVerbatim>[^{*\\@\x06~`\n\/]+ {
1424 outputArray(yyscanner,yytext,yyleng);
1426 <SkipCComment,SkipVerbatim>\n {
1427 yyextra->yyLineNr++;
1428 outputChar(yyscanner,'\n');
1430 <SkipCComment,SkipVerbatim>. {
1431 outputChar(yyscanner,*yytext);
1433 <CopyCComment>[^*a-z_A-Z\x80-\xFF\n]*[^*a-z_A-Z\x80-\xFF\\\n] {
1434 yyextra->defLitText+=yytext;
1435 yyextra->defText+=escapeAt(yytext);
1437 <CopyCComment>\\[\r]?\n {
1438 yyextra->defLitText+=yytext;
1439 yyextra->defText+=" ";
1440 yyextra->yyLineNr++;
1441 yyextra->yyMLines++;
1443 <CopyCComment>{CCE} {
1444 yyextra->defLitText+=yytext;
1445 yyextra->defText+=yytext;
1446 BEGIN(yyextra->lastCContext);
1449 yyextra->yyLineNr++;
1450 yyextra->defLitText+=yytext;
1451 yyextra->defText+=' ';
1453 <RemoveCComment>{CCE}{B}*"#" { // see bug 594021 for a usecase for this rule
1454 if (yyextra->lastCContext==SkipCPPBlock)
1463 <RemoveCComment>{CCE} { BEGIN(yyextra->lastCContext); }
1464 <RemoveCComment>{CPPC}
1465 <RemoveCComment>{CCS}
1466 <RemoveCComment>[^*\x06\n]+
1467 <RemoveCComment>\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
1469 <SkipCPPComment>[^\n\/\\@]+ {
1470 outputArray(yyscanner,yytext,yyleng);
1472 <SkipCPPComment,RemoveCPPComment>\n {
1474 BEGIN(yyextra->lastCPPContext);
1476 <SkipCPPComment>{CCS} {
1477 outputChar(yyscanner,'/');outputChar(yyscanner,'*');
1479 <SkipCPPComment>{CPPC} {
1480 outputChar(yyscanner,'/');outputChar(yyscanner,'/');
1482 <SkipCPPComment>[^\x06\@\\\n]+ {
1483 outputArray(yyscanner,yytext,yyleng);
1486 outputChar(yyscanner,*yytext);
1488 <RemoveCPPComment>{CCS}
1489 <RemoveCPPComment>{CPPC}
1490 <RemoveCPPComment>[^\x06\n]+
1492 <DefineText>"#"/{IDSTART} {
1493 outputChar(yyscanner,' ');
1494 yyextra->quoteArg=TRUE;
1495 yyextra->idStart=true;
1496 yyextra->defLitText+=yytext;
1498 <DefineText,CopyCComment>{ID} {
1499 yyextra->defLitText+=yytext;
1500 if (YY_START == DefineText) outputSpaces(yyscanner,yytext);
1501 if (yyextra->quoteArg)
1503 yyextra->defText+="\"";
1505 if (yyextra->defArgs>0)
1507 auto it = yyextra->argMap.find(yytext);
1508 if (it!=yyextra->argMap.end())
1511 yyextra->defText+='@';
1512 yyextra->defText+=QCString().setNum(n);
1516 if (yyextra->idStart)
1518 warn(yyextra->yyFileName,yyextra->yyLineNr,
1519 "'#' is not followed by a macro parameter '%s': '%s'",
1520 qPrint(yyextra->defName),qPrint(yyextra->defLitText.stripWhiteSpace()));
1522 yyextra->defText+=yytext;
1527 yyextra->defText+=yytext;
1529 if (yyextra->quoteArg)
1531 yyextra->defText+="\"";
1533 yyextra->quoteArg=FALSE;
1534 yyextra->idStart=false;
1537 yyextra->defLitText+=yytext;
1538 yyextra->defText+=yytext;
1540 <DefineText>\\[\r]?\n {
1541 yyextra->defLitText+=yytext;
1542 outputChar(yyscanner,'\n');
1543 yyextra->defText += ' ';
1544 yyextra->yyLineNr++;
1545 yyextra->yyMLines++;
1548 QCString comment=extractTrailingComment(yyextra->defLitText);
1549 yyextra->defText = yyextra->defText.stripWhiteSpace();
1550 if (yyextra->defText.startsWith("##"))
1552 warn(yyextra->yyFileName,yyextra->yyLineNr,
1553 "'##' cannot occur at the beginning of a macro definition '%s': '%s'",
1554 qPrint(yyextra->defName),qPrint(yyextra->defLitText.stripWhiteSpace()));
1556 else if (yyextra->defText.endsWith("##"))
1558 warn(yyextra->yyFileName,yyextra->yyLineNr,
1559 "'##' cannot occur at the end of a macro definition '%s': '%s'",
1560 qPrint(yyextra->defName),qPrint(yyextra->defLitText.stripWhiteSpace()));
1562 else if (yyextra->defText.endsWith("#"))
1564 warn(yyextra->yyFileName,yyextra->yyLineNr,
1565 "expected formal parameter after # in macro definition '%s': '%s'",
1566 qPrint(yyextra->defName),qPrint(yyextra->defLitText.stripWhiteSpace()));
1568 yyextra->defLitText+=yytext;
1569 if (!comment.isEmpty())
1571 outputString(yyscanner,comment);
1572 yyextra->defLitText=yyextra->defLitText.left(yyextra->defLitText.length()-comment.length()-1);
1574 outputChar(yyscanner,'\n');
1576 //printf("Define name='%s' text='%s' litTexti='%s'\n",qPrint(yyextra->defName),qPrint(yyextra->defText),qPrint(yyextra->defLitText));
1577 if (yyextra->includeStack.empty() || yyextra->curlyCount>0)
1579 addMacroDefinition(yyscanner);
1581 def=isDefined(yyscanner,yyextra->defName);
1582 if (def==0) // new define
1584 //printf("new define '%s'!\n",qPrint(yyextra->defName));
1585 addDefine(yyscanner);
1587 else if (def /*&& macroIsAccessible(def)*/)
1588 // name already exists
1590 //printf("existing define!\n");
1591 //printf("define found\n");
1592 if (def->undef) // undefined name
1595 def->name = yyextra->defName;
1596 def->definition = yyextra->defText.stripWhiteSpace();
1597 def->nargs = yyextra->defArgs;
1598 def->fileName = yyextra->yyFileName;
1599 def->lineNr = yyextra->yyLineNr-yyextra->yyMLines;
1600 def->columnNr = yyextra->yyColNr;
1604 //printf("error: define %s is defined more than once!\n",qPrint(yyextra->defName));
1607 yyextra->argMap.clear();
1608 yyextra->yyLineNr++;
1610 yyextra->lastGuardName.resize(0);
1613 <DefineText>{B}* { outputString(yyscanner,yytext);
1614 yyextra->defText += ' ';
1615 yyextra->defLitText+=yytext;
1617 <DefineText>{B}*"##"{B}* { outputString(yyscanner,substitute(yytext,"##"," "));
1618 yyextra->defText += "##";
1619 yyextra->defLitText+=yytext;
1621 <DefineText>"@" { outputString(yyscanner,substitute(yytext,"@@"," "));
1622 yyextra->defText += "@@";
1623 yyextra->defLitText+=yytext;
1626 outputChar(yyscanner,' ');
1627 yyextra->defText += *yytext;
1628 yyextra->defLitText+=yytext;
1629 if (!yyextra->insideComment)
1631 BEGIN(SkipDoubleQuote);
1635 outputChar(yyscanner,' ');
1636 yyextra->defText += *yytext;
1637 yyextra->defLitText+=yytext;
1638 if (!yyextra->insideComment)
1640 BEGIN(SkipSingleQuote);
1643 <SkipDoubleQuote>{CPPC}[/]? { outputSpaces(yyscanner,yytext);
1644 yyextra->defText += yytext;
1645 yyextra->defLitText+=yytext;
1647 <SkipDoubleQuote>{CCS}[*]? { outputSpaces(yyscanner,yytext);
1648 yyextra->defText += yytext;
1649 yyextra->defLitText+=yytext;
1651 <SkipDoubleQuote>\" {
1652 outputChar(yyscanner,' ');
1653 yyextra->defText += *yytext;
1654 yyextra->defLitText+=yytext;
1657 <SkipSingleQuote,SkipDoubleQuote>\\. {
1658 outputSpaces(yyscanner,yytext);
1659 yyextra->defText += yytext;
1660 yyextra->defLitText+=yytext;
1662 <SkipSingleQuote>\' {
1663 outputChar(yyscanner,' ');
1664 yyextra->defText += *yytext;
1665 yyextra->defLitText+=yytext;
1668 <SkipDoubleQuote,SkipSingleQuote>. { outputSpace(yyscanner,yytext[0]);
1669 yyextra->defText += *yytext;
1670 yyextra->defLitText += *yytext;
1672 <DefineText>. { outputSpace(yyscanner,yytext[0]);
1673 yyextra->defText += *yytext;
1674 yyextra->defLitText += *yytext;
1677 DBG_CTX((stderr,"End of include file\n"));
1678 //printf("Include stack depth=%d\n",yyextra->includeStack.size());
1679 if (yyextra->includeStack.empty())
1681 DBG_CTX((stderr,"Terminating scanner!\n"));
1686 QCString toFileName = yyextra->yyFileName;
1687 const std::unique_ptr<FileState> &fs=yyextra->includeStack.back();
1688 //fileDefineCache->merge(yyextra->yyFileName,fs->fileName);
1689 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
1690 yy_switch_to_buffer( fs->bufState, yyscanner );
1691 yy_delete_buffer( oldBuf, yyscanner );
1692 yyextra->yyLineNr = fs->lineNr;
1693 //preYYin = fs->oldYYin;
1694 yyextra->inputBuf = fs->oldFileBuf;
1695 yyextra->inputBufPos = fs->oldFileBufPos;
1696 yyextra->curlyCount = fs->curlyCount;
1697 setFileName(yyscanner,fs->fileName);
1698 DBG_CTX((stderr,"######## FileName %s\n",qPrint(yyextra->yyFileName)));
1700 // Deal with file changes due to
1701 // #include's within { .. } blocks
1702 QCString lineStr(15+yyextra->yyFileName.length());
1703 lineStr.sprintf("# %d \"%s\" 2",yyextra->yyLineNr,qPrint(yyextra->yyFileName));
1704 outputString(yyscanner,lineStr);
1706 yyextra->includeStack.pop_back();
1709 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
1710 // to avoid deadlocks we allow multiple threads to process the same header file.
1711 // The first one to finish will store the results globally. After that the
1712 // next time the same file is encountered, the stored data is used and the file
1713 // is not processed again.
1714 if (!g_defineManager.alreadyProcessed(toFileName.str()))
1716 // now that the file is completely processed, prevent it from processing it again
1717 g_defineManager.addInclude(yyextra->yyFileName.str(),toFileName.str());
1718 g_defineManager.store(toFileName.str(),yyextra->localDefines);
1722 if (Debug::isFlagSet(Debug::Preprocessor))
1724 Debug::print(Debug::Preprocessor,0,"#include %s: was already processed by another thread! not storing data...\n",qPrint(toFileName));
1728 // move the local macros definitions for in this file to the translation unit context
1729 for (const auto &kv : yyextra->localDefines)
1731 auto pair = yyextra->contextDefines.insert(kv);
1732 if (!pair.second) // define already in context -> replace with local version
1734 yyextra->contextDefines.erase(pair.first);
1735 yyextra->contextDefines.insert(kv);
1738 yyextra->localDefines.clear();
1743 if (YY_START==SkipVerbatim || YY_START==SkipCond)
1749 outputArray(yyscanner,yytext,yyleng);
1750 yyextra->lastCContext=YY_START;
1751 yyextra->commentCount=1;
1754 yyextra->isSpecialComment = true;
1755 yyextra->lastGuardName.resize(0); // reset guard in case the #define is documented!
1759 yyextra->isSpecialComment = false;
1761 BEGIN(SkipCComment);
1765 if (YY_START==SkipVerbatim || YY_START==SkipCond || getLanguageFromFileName(yyextra->yyFileName)==SrcLangExt_Fortran)
1771 outputArray(yyscanner,yytext,yyleng);
1772 yyextra->lastCPPContext=YY_START;
1775 yyextra->isSpecialComment = true;
1776 yyextra->lastGuardName.resize(0); // reset guard in case the #define is documented!
1780 yyextra->isSpecialComment = false;
1782 BEGIN(SkipCPPComment);
1786 outputChar(yyscanner,'\n');
1787 yyextra->yyLineNr++;
1790 yyextra->expectGuard = FALSE;
1791 outputChar(yyscanner,*yytext);
1796 /////////////////////////////////////////////////////////////////////////////////////
1798 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
1800 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1801 yy_size_t bytesInBuf = state->inputBuf->curPos()-state->inputBufPos;
1802 yy_size_t bytesToCopy = std::min(max_size,bytesInBuf);
1803 memcpy(buf,state->inputBuf->data()+state->inputBufPos,bytesToCopy);
1804 state->inputBufPos+=bytesToCopy;
1808 static void setFileName(yyscan_t yyscanner,const QCString &name)
1810 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1812 FileInfo fi(name.str());
1813 state->yyFileName=fi.absFilePath();
1814 state->yyFileDef=findFileDef(Doxygen::inputNameLinkedMap,state->yyFileName,ambig);
1815 if (state->yyFileDef==0) // if this is not an input file check if it is an
1818 state->yyFileDef=findFileDef(Doxygen::includeNameLinkedMap,state->yyFileName,ambig);
1820 //printf("setFileName(%s) state->yyFileName=%s state->yyFileDef=%p\n",
1821 // name,qPrint(state->yyFileName),state->yyFileDef);
1822 if (state->yyFileDef && state->yyFileDef->isReference()) state->yyFileDef=0;
1823 state->insideCS = getLanguageFromFileName(state->yyFileName)==SrcLangExt_CSharp;
1824 state->insideFtn = getLanguageFromFileName(state->yyFileName)==SrcLangExt_Fortran;
1825 state->isSource = guessSection(state->yyFileName);
1828 static void incrLevel(yyscan_t yyscanner)
1830 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1831 state->levelGuard.push(false);
1832 //printf("%s line %d: incrLevel %d\n",qPrint(yyextra->yyFileName),yyextra->yyLineNr,yyextra->levelGuard.size());
1835 static void decrLevel(yyscan_t yyscanner)
1837 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1838 //printf("%s line %d: decrLevel %d\n",qPrint(state->yyFileName),state->yyLineNr,state->levelGuard.size());
1839 if (!state->levelGuard.empty())
1841 state->levelGuard.pop();
1845 warn(state->yyFileName,state->yyLineNr,"More #endif's than #if's found.\n");
1849 static bool otherCaseDone(yyscan_t yyscanner)
1851 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1852 if (state->levelGuard.empty())
1854 warn(state->yyFileName,state->yyLineNr,"Found an #else without a preceding #if.\n");
1859 return state->levelGuard.top();
1863 static void setCaseDone(yyscan_t yyscanner,bool value)
1865 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1866 state->levelGuard.top()=value;
1870 static FileState *checkAndOpenFile(yyscan_t yyscanner,const QCString &fileName,bool &alreadyProcessed)
1872 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1873 alreadyProcessed = FALSE;
1875 //printf("checkAndOpenFile(%s)\n",qPrint(fileName));
1876 FileInfo fi(fileName.str());
1877 if (fi.exists() && fi.isFile())
1879 const StringVector &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
1880 if (patternMatch(fi,exclPatterns)) return 0;
1882 QCString absName = fi.absFilePath();
1885 if (state->curlyCount==0) // not #include inside { ... }
1887 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
1888 if (g_defineManager.alreadyProcessed(absName.str()))
1890 alreadyProcessed = TRUE;
1891 //printf(" already included 1\n");
1892 return 0; // already done
1895 // check include stack for absName
1897 alreadyProcessed = std::any_of(
1898 state->includeStack.begin(),
1899 state->includeStack.end(),
1900 [absName](const std::unique_ptr<FileState> &lfs)
1901 { return lfs->fileName==absName; }
1904 if (alreadyProcessed)
1906 //printf(" already included 2\n");
1909 //printf("#include %s\n",qPrint(absName));
1911 fs = new FileState(static_cast<uint>(fi.size())+4096);
1912 if (!readInputFile(absName,fs->fileBuf))
1914 //printf(" error reading\n");
1920 fs->oldFileBuf = state->inputBuf;
1921 fs->oldFileBufPos = state->inputBufPos;
1927 static FileState *findFile(yyscan_t yyscanner, const QCString &fileName,bool localInclude,bool &alreadyProcessed)
1929 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1930 //printf("** findFile(%s,%d) state->yyFileName=%s\n",qPrint(fileName),localInclude,qPrint(state->yyFileName));
1931 if (Portable::isAbsolutePath(fileName))
1933 FileState *fs = checkAndOpenFile(yyscanner,fileName,alreadyProcessed);
1936 setFileName(yyscanner,fileName);
1940 else if (alreadyProcessed)
1945 if (localInclude && !state->yyFileName.isEmpty())
1947 FileInfo fi(state->yyFileName.str());
1950 QCString absName = QCString(fi.dirPath(TRUE))+"/"+fileName;
1951 FileState *fs = checkAndOpenFile(yyscanner,absName,alreadyProcessed);
1954 setFileName(yyscanner,absName);
1958 else if (alreadyProcessed)
1964 if (state->pathList.empty())
1968 for (auto path : state->pathList)
1970 std::string absName = (path+"/"+fileName).str();
1971 //printf(" Looking for %s in %s\n",fileName,path.c_str());
1972 FileState *fs = checkAndOpenFile(yyscanner,absName.c_str(),alreadyProcessed);
1975 setFileName(yyscanner,absName.c_str());
1977 //printf(" -> found it\n");
1980 else if (alreadyProcessed)
1988 static QCString extractTrailingComment(const QCString &s)
1990 if (s.isEmpty()) return "";
1991 int i=(int)s.length()-1;
2000 if (i>=0 && s[i]=='*') // end of a comment block
2003 while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--;
2008 // only /*!< or /**< are treated as a comment for the macro name,
2009 // otherwise the comment is treated as part of the macro definition
2010 return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : "";
2018 // whitespace or line-continuation
2033 static int getNextChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos);
2034 static int getCurrentChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint pos);
2035 static void unputChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos,char c);
2036 static bool expandExpression(yyscan_t yyscanner,QCString &expr,QCString *rest,int pos,int level);
2038 static QCString stringize(const QCString &s)
2042 bool inString=FALSE;
2045 while (i<s.length())
2047 if (!inString && !inChar)
2049 while (i<s.length() && !inString && !inChar)
2070 while (i<s.length() && inChar)
2091 while (i<s.length() && inString)
2107 //printf("stringize '%s'->'%s'\n",qPrint(s),qPrint(result));
2111 /*! Execute all ## operators in expr.
2112 * If the macro name before or after the operator contains a no-rescan
2113 * marker (@-) then this is removed (before the concatenated macro name
2114 * may be expanded again.
2116 static void processConcatOperators(QCString &expr)
2118 if (expr.isEmpty()) return;
2119 //printf("processConcatOperators: in='%s'\n",qPrint(expr));
2120 std::string e = expr.str();
2121 static const reg::Ex r(R"(\s*##\s*)");
2127 reg::Iterator it(e,r,i);
2130 const auto &match = *it;
2131 size_t n = match.position();
2132 size_t l = match.length();
2133 //printf("Match: '%s'\n",qPrint(expr.mid(i)));
2134 if (n+l+1<e.length() && e[static_cast<int>(n+l)]=='@' && expr[static_cast<int>(n+l+1)]=='-')
2136 // remove no-rescan marker after ID
2139 //printf("found '%s'\n",qPrint(expr.mid(n,l)));
2140 // remove the ## operator and the surrounding whitespace
2141 e=e.substr(0,n)+e.substr(n+l);
2142 int k=static_cast<int>(n)-1;
2143 while (k>=0 && isId(e[k])) k--;
2144 if (k>0 && e[k]=='-' && e[k-1]=='@')
2146 // remove no-rescan marker before ID
2147 e=e.substr(0,k-1)+e.substr(k+1);
2160 //printf("processConcatOperators: out='%s'\n",qPrint(expr));
2163 static void returnCharToStream(yyscan_t yyscanner,char c)
2165 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
2169 static inline void addTillEndOfString(yyscan_t yyscanner,const QCString &expr,QCString *rest,
2170 uint &pos,char term,QCString &arg)
2173 while ((cc=getNextChar(yyscanner,expr,rest,pos))!=EOF && cc!=0)
2175 if (cc=='\\') arg+=(char)cc,cc=getNextChar(yyscanner,expr,rest,pos);
2176 else if (cc==term) return;
2181 /*! replaces the function macro \a def whose argument list starts at
2182 * \a pos in expression \a expr.
2183 * Notice that this routine may scan beyond the \a expr string if needed.
2184 * In that case the characters will be read from the input file.
2185 * The replacement string will be returned in \a result and the
2186 * length of the (unexpanded) argument list is stored in \a len.
2188 static bool replaceFunctionMacro(yyscan_t yyscanner,const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result,int level)
2190 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2191 //printf(">replaceFunctionMacro(expr='%s',rest='%s',pos=%d,def='%s') level=%d\n",qPrint(expr),rest ? qPrint(*rest) : 0,pos,qPrint(def->name),state->levelGuard.size());
2196 while ((cc=getCurrentChar(yyscanner,expr,rest,j))!=EOF && isspace(cc))
2199 getNextChar(yyscanner,expr,rest,j);
2203 unputChar(yyscanner,expr,rest,j,' ');
2206 getNextChar(yyscanner,expr,rest,j); // eat the '(' character
2208 std::map<std::string,std::string> argTable; // list of arguments
2213 // PHASE 1: read the macro arguments
2216 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2224 while (!done && (argCount<def->nargs || def->varArgs) &&
2225 ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2229 if (c=='(') // argument is a function => search for matching )
2234 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2237 //printf("processing %c: term=%c (%d)\n",c,term,term);
2238 if (c=='\'' || c=='\"') // skip ('s and )'s inside strings
2241 addTillEndOfString(yyscanner,expr,rest,j,c,arg);
2258 else if (c==')' || c==',') // last or next argument found
2260 if (c==',' && argCount==def->nargs-1 && def->varArgs)
2262 arg=arg.stripWhiteSpace();
2268 argKey.sprintf("@%d",argCount++); // key name
2269 arg=arg.stripWhiteSpace();
2270 // add argument to the lookup table
2271 argTable.emplace(toStdString(argKey), toStdString(arg));
2273 if (c==')') // end of the argument list
2279 else if (c=='\"') // append literal strings
2283 while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2290 if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break;
2296 else if (c=='\'') // append literal characters
2300 while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2307 if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break;
2313 else if (c=='/') // possible start of a comment
2315 char prevChar = '\0';
2317 if ((cc=getCurrentChar(yyscanner,expr,rest,j)) == '*') // we have a comment
2319 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2323 if (c == '/' && prevChar == '*') break; // we have an end of comment
2328 else // append other characters
2335 // PHASE 2: apply the macro function
2336 if (argCount==def->nargs || // same number of arguments
2337 (argCount>=def->nargs-1 && def->varArgs)) // variadic macro with at least as many
2338 // params as the non-variadic part (see bug731985)
2341 // substitution of all formal arguments
2343 const QCString d=def->definition.stripWhiteSpace();
2344 //printf("Macro definition: '%s'\n",qPrint(d));
2345 bool inString=FALSE;
2346 while (k<d.length())
2348 if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
2350 if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
2353 resExpr+="@@"; // we unescape these later
2355 else if (d.at(k+1)=='-') // no-rescan marker
2360 else // argument marker => read the argument number
2365 // search for ## backward
2366 if (l>=0 && d.at(l)=='"') l--;
2367 while (l>=0 && d.at(l)==' ') l--;
2368 if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
2371 while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
2374 // search for ## forward
2376 if (l<(int)d.length() && d.at(l)=='"') l++;
2377 while (l<(int)d.length() && d.at(l)==' ') l++;
2378 if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
2380 //printf("request key %s result %s\n",qPrint(key),argTable[key]->data());
2381 auto it = argTable.find(key.str());
2382 if (it!=argTable.end())
2384 QCString substArg = it->second.c_str();
2385 //printf("substArg='%s'\n",qPrint(substArg));
2386 // only if no ## operator is before or after the argument
2387 // marker we do macro expansion.
2390 expandExpression(yyscanner,substArg,0,0,level+1);
2394 //printf("'%s'=stringize('%s')\n",qPrint(stringize(*subst)),subst->data());
2396 // if the marker is inside a string (because a # was put
2397 // before the macro name) we must escape " and \ characters
2398 resExpr+=stringize(substArg);
2402 if (hash && substArg.isEmpty())
2404 resExpr+="@E"; // empty argument will be remove later on
2406 else if (state->nospaces)
2412 resExpr+=" "+substArg+" ";
2418 else // no marker, just copy
2420 if (!inString && d.at(k)=='\"')
2422 inString=TRUE; // entering a literal string
2424 else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
2426 inString=FALSE; // leaving a literal string
2433 //printf("<replaceFunctionMacro(expr='%s',rest='%s',pos=%d,def='%s',result='%s') level=%d return=TRUE\n",qPrint(expr),rest ? qPrint(*rest) : 0,pos,qPrint(def->name),qPrint(result),state->levelGuard.size());
2436 //printf("<replaceFunctionMacro(expr='%s',rest='%s',pos=%d,def='%s',result='%s') level=%d return=FALSE\n",qPrint(expr),rest ? qPrint(*rest) : 0,pos,qPrint(def->name),qPrint(result),state->levelGuard.size());
2441 /*! returns the next identifier in string \a expr by starting at position \a p.
2442 * The position of the identifier is returned (or -1 if nothing is found)
2443 * and \a l is its length. Any quoted strings are skipping during the search.
2445 static int getNextId(const QCString &expr,int p,int *l)
2448 while (p<(int)expr.length())
2450 char c=expr.at(p++);
2451 if (isdigit(c)) // skip number
2453 while (p<(int)expr.length() && isId(expr.at(p))) p++;
2455 else if (isalpha(c) || c=='_') // read id
2458 while (p<(int)expr.length() && isId(expr.at(p))) p++;
2462 else if (c=='"') // skip string
2465 if (p<(int)expr.length()) c=expr.at(p);
2466 while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\')))
2467 // continue as long as no " is found, but ignoring \", but not \\"
2474 if (p<(int)expr.length()) ++p; // skip closing quote
2476 else if (c=='/') // skip C Comment
2478 //printf("Found C comment at p=%d\n",p);
2480 if (p<(int)expr.length())
2483 if (c=='*') // Start of C comment
2486 while (p<(int)expr.length() && !(pc=='*' && c=='/'))
2493 //printf("Found end of C comment at p=%d\n",p);
2499 #define MAX_EXPANSION_DEPTH 50
2501 /*! performs recursive macro expansion on the string \a expr
2502 * starting at position \a pos.
2503 * May read additional characters from the input while re-scanning!
2505 static bool expandExpression(yyscan_t yyscanner,QCString &expr,QCString *rest,int pos,int level)
2507 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2508 //printf(">expandExpression(expr='%s',rest='%s',pos=%d,level=%d)\n",qPrint(expr),rest ? qPrint(*rest) : "", pos, level);
2511 //printf("<expandExpression: empty\n");
2514 if (state->expanded.find(expr.str())!=state->expanded.end() &&
2515 level>MAX_EXPANSION_DEPTH) // check for too deep recursive expansions
2517 //printf("<expandExpression: already expanded expr='%s'\n",qPrint(expr));
2522 state->expanded.insert(expr.str());
2526 bool definedTest=FALSE;
2530 while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
2532 bool replaced=FALSE;
2533 macroName=expr.mid(p,l);
2534 //printf(" p=%d macroName=%s\n",p,qPrint(macroName));
2535 if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
2537 if (state->expandedDict.find(macroName.str())==state->expandedDict.end()) // expand macro
2539 Define *def=isDefined(yyscanner,macroName);
2540 if (macroName=="defined")
2542 //printf("found defined inside macro definition '%s'\n",qPrint(expr.right(expr.length()-p)));
2545 else if (definedTest) // macro name was found after defined
2547 if (def) expMacro = " 1 "; else expMacro = " 0 ";
2552 else if (def && def->nargs==-1) // simple macro
2554 // substitute the definition of the macro
2555 //printf("macro '%s'->'%s'\n",qPrint(macroName),qPrint(def->definition));
2556 if (state->nospaces)
2558 expMacro=def->definition.stripWhiteSpace();
2562 expMacro=" "+def->definition.stripWhiteSpace()+" ";
2564 //expMacro=def->definition.stripWhiteSpace();
2567 //printf("simple macro expansion='%s'->'%s'\n",qPrint(macroName),qPrint(expMacro));
2569 else if (def && def->nargs>=0) // function macro
2571 //printf(" >>>> call replaceFunctionMacro expr='%s'\n",qPrint(expr));
2572 replaced=replaceFunctionMacro(yyscanner,expr,rest,p+l,len,def,expMacro,level);
2573 //printf(" <<<< call replaceFunctionMacro: replaced=%d\n",replaced);
2576 //printf(" macroName='%s' expMacro='%s' replaced=%d\n",qPrint(macroName),qPrint(expMacro),replaced);
2578 if (replaced) // expand the macro and rescan the expression
2580 //printf(" replacing '%s'->'%s'\n",expr.mid(p,qPrint(len)),qPrint(expMacro));
2581 QCString resultExpr=expMacro;
2582 QCString restExpr=expr.right(expr.length()-len-p);
2583 processConcatOperators(resultExpr);
2584 //printf(" macroName=%s restExpr='%s' def->nonRecursive=%d\n",qPrint(macroName),qPrint(restExpr),def->nonRecursive);
2585 bool expanded=false;
2586 if (def && !def->nonRecursive)
2588 state->expandedDict.emplace(toStdString(macroName),def);
2589 expanded = expandExpression(yyscanner,resultExpr,&restExpr,0,level+1);
2590 state->expandedDict.erase(toStdString(macroName));
2592 else if (def && def->nonRecursive)
2598 expr=expr.left(p)+resultExpr+restExpr;
2599 //printf(" new expression: '%s' old i=%d new i=%d\n",qPrint(expr),i,p);
2604 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
2608 else // move to the next macro name
2610 //printf(" moving to the next macro old i=%d new i=%d\n",i,p+l);
2614 else // move to the next macro name
2616 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
2617 //printf("macro already expanded, moving to the next macro expr=%s\n",qPrint(expr));
2621 // check for too many inplace expansions without making progress
2631 if (samePosCount>MAX_EXPANSION_DEPTH)
2636 else // no re-scan marker found, skip the macro name
2638 //printf("skipping marked macro\n");
2642 //printf("<expandExpression(expr='%s',rest='%s',pos=%d,level=%d)\n",qPrint(expr),rest ? qPrint(*rest) : "", pos,level);
2646 /*! @brief Process string or character literal.
2648 * \a inputStr should point to the start of a string or character literal.
2649 * the routine will return a pointer to just after the end of the literal
2650 * the character making up the literal will be added to \a result.
2652 static const char *processUntilMatchingTerminator(const char *inputStr,QCString &result)
2654 if (inputStr==0) return inputStr;
2655 char term = *inputStr; // capture start character of the literal
2656 if (term!='\'' && term!='"') return inputStr; // not a valid literal
2658 // output start character
2661 while ((c=*inputStr)) // while inside the literal
2663 if (c==term) // found end marker of the literal
2665 // output end character and stop
2670 else if (c=='\\') // escaped character, process next character
2671 // as well without checking for end marker.
2676 if (c==0) break; // unexpected end of string after escape character
2684 /*! replaces all occurrences of @@@@ in \a s by @@
2685 * and removes all occurrences of @@E.
2686 * All identifiers found are replaced by 0L
2688 static QCString removeIdsAndMarkers(const QCString &s)
2690 //printf("removeIdsAndMarkers(%s)\n",s);
2691 if (s.isEmpty()) return s;
2692 const char *p=s.data();
2700 if (c=='@') // replace @@ with @ and remove @E
2706 else if (*(p+1)=='E')
2712 else if (isdigit(c)) // number
2718 else if (c=='\'') // quoted character
2720 p = processUntilMatchingTerminator(p,result);
2722 else if (c=='d' && !inNum) // identifier starting with a 'd'
2724 if (qstrncmp(p,"defined ",8)==0 || qstrncmp(p,"defined(",8)==0)
2727 p+=7; // skip defined
2733 while ((c=*p) && isId(c)) p++;
2736 else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
2740 while ((c=*p) && isId(c)) p++;
2741 while ((c=*p) && isspace((uchar)c)) p++;
2742 if (*p=='(') // undefined function macro
2748 if (c=='(') count++;
2752 if (count==0) break;
2758 if (c=='*') // start of C comment
2760 while (*p && !(pc=='*' && c=='/')) // search end of comment
2771 else if (c=='/') // skip C comments
2775 if (c=='*') // start of C comment
2777 while (*p && !(pc=='*' && c=='/')) // search end of comment
2784 else // oops, not comment but division
2794 char lc=(char)tolower(c);
2795 if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE;
2800 //printf("removeIdsAndMarkers(%s)=%s\n",s,qPrint(result));
2804 /*! replaces all occurrences of @@ in \a s by @
2806 * \a s only contains pairs of @@'s
2808 static QCString removeMarkers(const QCString &s)
2810 if (s.isEmpty()) return s;
2811 const char *p=s.data();
2820 case '@': // replace @@ with @
2829 case '/': // skip C comments
2834 if (c=='*') // start of C comment
2836 while (*p && !(pc=='*' && c=='/')) // search end of comment
2838 if (*p=='@' && *(p+1)=='@')
2845 if (*p) result+=c,p++;
2849 case '"': // skip string literals
2850 case '\'': // skip char literals
2851 p = processUntilMatchingTerminator(p,result);
2862 //printf("RemoveMarkers(%s)=%s\n",s,qPrint(result));
2866 /*! compute the value of the expression in string \a expr.
2867 * If needed the function may read additional characters from the input.
2870 static bool computeExpression(yyscan_t yyscanner,const QCString &expr)
2872 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2874 state->expanded.clear();
2875 expandExpression(yyscanner,e,0,0,0);
2876 //printf("after expansion '%s'\n",qPrint(e));
2877 e = removeIdsAndMarkers(e);
2878 if (e.isEmpty()) return FALSE;
2879 //printf("parsing '%s'\n",qPrint(e));
2880 return state->constExpParser.parse(state->yyFileName.data(),state->yyLineNr,e.str());
2883 /*! expands the macro definition in \a name
2884 * If needed the function may read additional characters from the input
2887 static QCString expandMacro(yyscan_t yyscanner,const QCString &name)
2889 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2891 state->expanded.clear();
2892 expandExpression(yyscanner,n,0,0,0);
2894 //printf("expandMacro '%s'->'%s'\n",qPrint(name),qPrint(n));
2898 static void addDefine(yyscan_t yyscanner)
2900 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2902 def.name = state->defName;
2903 def.definition = state->defText.stripWhiteSpace();
2904 def.nargs = state->defArgs;
2905 def.fileName = state->yyFileName;
2906 def.fileDef = state->yyFileDef;
2907 def.lineNr = state->yyLineNr-state->yyMLines;
2908 def.columnNr = state->yyColNr;
2909 def.varArgs = state->defVarArgs;
2910 //printf("newDefine: %s %s file: %s\n",qPrint(def.name),qPrint(def.definition),
2911 // def.fileDef ? qPrint(def.fileDef->name()) : qPrint(def.fileName));
2912 //printf("newDefine: '%s'->'%s'\n",qPrint(def.name),qPrint(def.definition));
2913 if (!def.name.isEmpty() &&
2914 Doxygen::expandAsDefinedSet.find(def.name.str())!=Doxygen::expandAsDefinedSet.end())
2916 def.isPredefined=TRUE;
2918 auto it = state->localDefines.find(def.name.str());
2919 if (it!=state->localDefines.end()) // redefine
2921 state->localDefines.erase(it);
2923 state->localDefines.insert(std::make_pair(def.name.str(),def));
2926 static void addMacroDefinition(yyscan_t yyscanner)
2928 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2929 if (state->skip) return; // do not add this define as it is inside a
2930 // conditional section (cond command) that is disabled.
2933 define.fileName = state->yyFileName;
2934 define.lineNr = state->yyLineNr - state->yyMLines;
2935 define.columnNr = state->yyColNr;
2936 define.name = state->defName;
2937 define.args = state->defArgsStr;
2938 define.fileDef = state->inputFileDef;
2940 QCString litText = state->defLitText;
2941 int l=litText.find('\n');
2942 if (l>0 && litText.left(l).stripWhiteSpace()=="\\")
2944 // strip first line if it only contains a slash
2945 litText = litText.right(litText.length()-l-1);
2949 // align the items on the first line with the items on the second line
2951 const char *p=litText.data()+k;
2953 while ((c=*p++) && (c==' ' || c=='\t')) k++;
2954 litText=litText.mid(l+1,k-l-1)+litText.stripWhiteSpace();
2956 QCString litTextStripped = state->defLitText.stripWhiteSpace();
2957 if (litTextStripped.contains('\n')>=1)
2959 define.definition = litText;
2963 define.definition = litTextStripped;
2966 state->macroDefinitions.push_back(define);
2970 static inline void outputChar(yyscan_t yyscanner,char c)
2972 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2973 if (state->includeStack.empty() || state->curlyCount>0) state->outputBuf->addChar(c);
2976 static inline void outputArray(yyscan_t yyscanner,const char *a,yy_size_t len)
2978 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2979 if (state->includeStack.empty() || state->curlyCount>0) state->outputBuf->addArray(a,static_cast<uint>(len));
2982 static inline void outputString(yyscan_t yyscanner,const QCString &a)
2984 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2985 if (state->includeStack.empty() || state->curlyCount>0) state->outputBuf->addArray(a.data(),a.length());
2988 static inline void outputSpace(yyscan_t yyscanner,char c)
2990 if (c=='\t') outputChar(yyscanner,'\t');
2991 else outputChar(yyscanner,' ');
2994 static inline void outputSpaces(yyscan_t yyscanner,char *s)
3000 if (c=='\t') outputChar(yyscanner,'\t');
3001 else outputChar(yyscanner,' ');
3005 static inline void extraSpacing(yyscan_t yyscanner)
3007 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3008 if (!yyextra->defContinue) return;
3009 for (int i=0; i< (int)yyleng; i++)
3011 if (yytext[i] == '\t')
3012 yyextra->defExtraSpacing+='\t';
3014 yyextra->defExtraSpacing+=' ';
3018 static QCString determineAbsoluteIncludeName(const QCString &curFile,const QCString &incFileName)
3020 bool searchIncludes = Config_getBool(SEARCH_INCLUDES);
3021 QCString absIncFileName = incFileName;
3022 FileInfo fi(curFile.str());
3025 QCString absName = QCString(fi.dirPath(TRUE))+"/"+incFileName;
3026 FileInfo fi2(absName.str());
3029 absIncFileName=fi2.absFilePath();
3031 else if (searchIncludes) // search in INCLUDE_PATH as well
3033 const StringVector &includePath = Config_getList(INCLUDE_PATH);
3034 for (const auto &incPath : includePath)
3036 FileInfo fi3(incPath);
3037 if (fi3.exists() && fi3.isDir())
3039 absName = QCString(fi3.absFilePath())+"/"+incFileName;
3040 //printf("trying absName=%s\n",qPrint(absName));
3041 FileInfo fi4(absName.str());
3044 absIncFileName=fi4.absFilePath();
3047 //printf( "absIncFileName = %s\n", qPrint(absIncFileName) );
3051 //printf( "absIncFileName = %s\n", qPrint(absIncFileName) );
3053 return absIncFileName;
3056 static void readIncludeFile(yyscan_t yyscanner,const QCString &inc)
3058 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3061 // find the start of the include file name
3062 while (i<inc.length() &&
3063 (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
3067 // was it a local include?
3068 bool localInclude = s>0 && inc.at(s-1)=='"';
3070 // find the end of the include file name
3071 while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
3073 if (s<inc.length() && i>s) // valid include file name found
3075 // extract include path+name
3076 QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
3078 QCString dosExt = incFileName.right(4);
3079 if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb")
3081 // skip imported binary files (e.g. M$ type libraries)
3085 QCString oldFileName = state->yyFileName;
3086 FileDef *oldFileDef = state->yyFileDef;
3087 int oldLineNr = state->yyLineNr;
3088 //printf("Searching for '%s'\n",qPrint(incFileName));
3090 QCString absIncFileName = determineAbsoluteIncludeName(state->yyFileName,incFileName);
3092 // findFile will overwrite state->yyFileDef if found
3094 bool alreadyProcessed = FALSE;
3095 //printf("calling findFile(%s)\n",qPrint(incFileName));
3096 if ((fs=findFile(yyscanner,incFileName,localInclude,alreadyProcessed))) // see if the include file can be found
3099 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
3100 g_defineManager.addInclude(oldFileName.str(),absIncFileName.str());
3103 //printf("Found include file!\n");
3104 if (Debug::isFlagSet(Debug::Preprocessor))
3106 for (i=0;i<state->includeStack.size();i++)
3108 Debug::print(Debug::Preprocessor,0," ");
3110 Debug::print(Debug::Preprocessor,0,"#include %s: parsing...\n",qPrint(incFileName));
3113 if (state->includeStack.empty() && oldFileDef)
3115 PreIncludeInfo *ii = state->includeRelations.find(absIncFileName);
3119 FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
3120 state->includeRelations.add(
3123 ambig?nullptr:incFd,
3131 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3132 fs->bufState = YY_CURRENT_BUFFER;
3133 fs->lineNr = oldLineNr;
3134 fs->fileName = oldFileName;
3135 fs->curlyCount = state->curlyCount;
3136 state->curlyCount = 0;
3137 // push the state on the stack
3138 state->includeStack.emplace_back(fs);
3139 // set the scanner to the include file
3141 // Deal with file changes due to
3142 // #include's within { .. } blocks
3143 QCString lineStr(state->yyFileName.length()+20);
3144 lineStr.sprintf("# 1 \"%s\" 1\n",qPrint(state->yyFileName));
3145 outputString(yyscanner,lineStr);
3147 DBG_CTX((stderr,"Switching to include file %s\n",qPrint(incFileName)));
3148 state->expectGuard=TRUE;
3149 state->inputBuf = &fs->fileBuf;
3150 state->inputBufPos=0;
3151 yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE, yyscanner),yyscanner);
3155 if (alreadyProcessed) // if this header was already process we can just copy the stored macros
3156 // in the local context
3158 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
3159 g_defineManager.addInclude(state->yyFileName.str(),absIncFileName.str());
3160 g_defineManager.retrieve(absIncFileName.str(),state->contextDefines);
3163 if (state->includeStack.empty() && oldFileDef)
3165 PreIncludeInfo *ii = state->includeRelations.find(absIncFileName);
3169 FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
3170 ii = state->includeRelations.add(absIncFileName,
3180 if (Debug::isFlagSet(Debug::Preprocessor))
3182 for (i=0;i<state->includeStack.size();i++)
3184 Debug::print(Debug::Preprocessor,0," ");
3186 if (alreadyProcessed)
3188 Debug::print(Debug::Preprocessor,0,"#include %s: already processed! skipping...\n",qPrint(incFileName));
3192 Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",qPrint(incFileName));
3194 //printf("error: include file %s not found\n",yytext);
3196 if (state->curlyCount>0 && !alreadyProcessed) // failed to find #include inside { ... }
3198 warn(state->yyFileName,state->yyLineNr,"include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",qPrint(incFileName));
3204 /* ----------------------------------------------------------------- */
3206 static void startCondSection(yyscan_t yyscanner,const QCString §Id)
3208 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3209 //printf("startCondSection: skip=%d stack=%d\n",state->skip,state->condStack.size());
3211 bool expResult = prs.parse(state->yyFileName.data(),state->yyLineNr,sectId.data());
3212 state->condStack.emplace(std::make_unique<preYY_CondCtx>(state->yyLineNr,sectId,state->skip));
3217 //printf(" expResult=%d skip=%d\n",expResult,state->skip);
3220 static void endCondSection(yyscan_t yyscanner)
3222 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3223 if (state->condStack.empty())
3229 const std::unique_ptr<preYY_CondCtx> &ctx = state->condStack.top();
3230 state->skip=ctx->skip;
3231 state->condStack.pop();
3233 //printf("endCondSection: skip=%d stack=%d\n",state->skip,state->condStack.count());
3236 static void forceEndCondSection(yyscan_t yyscanner)
3238 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3239 while (!state->condStack.empty())
3241 state->condStack.pop();
3246 static QCString escapeAt(const QCString &text)
3249 if (!text.isEmpty())
3252 const char *p=text.data();
3255 if (c=='@') result+="@@"; else result+=c;
3261 static char resolveTrigraph(char c)
3265 case '=': return '#';
3266 case '/': return '\\';
3267 case '\'': return '^';
3268 case '(': return '[';
3269 case ')': return ']';
3270 case '!': return '|';
3271 case '<': return '{';
3272 case '>': return '}';
3273 case '-': return '~';
3278 /*@ ----------------------------------------------------------------------------
3281 static int getNextChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos)
3283 //printf("getNextChar(%s,%s,%d)\n",qPrint(expr),rest ? rest->data() : 0,pos);
3284 if (pos<expr.length())
3286 //printf("%c=expr()\n",expr.at(pos));
3287 return expr.at(pos++);
3289 else if (rest && !rest->isEmpty())
3292 *rest=rest->right(rest->length()-1);
3293 //printf("%c=rest\n",cc);
3298 int cc=yyinput(yyscanner);
3299 //printf("%d=yyinput() %d\n",cc,EOF);
3304 static int getCurrentChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint pos)
3306 //printf("getCurrentChar(%s,%s,%d)\n",qPrint(expr),rest ? rest->data() : 0,pos);
3307 if (pos<expr.length())
3309 //printf("%c=expr()\n",expr.at(pos));
3310 return expr.at(pos);
3312 else if (rest && !rest->isEmpty())
3315 //printf("%c=rest\n",cc);
3320 int cc=yyinput(yyscanner);
3321 returnCharToStream(yyscanner,(char)cc);
3322 //printf("%c=yyinput()\n",cc);
3327 static void unputChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos,char c)
3329 //printf("unputChar(%s,%s,%d,%c)\n",qPrint(expr),rest ? rest->data() : 0,pos,c);
3330 if (pos<expr.length())
3336 //printf("Prepending to rest!\n");
3337 char cs[2];cs[0]=c;cs[1]='\0';
3343 returnCharToStream(yyscanner,c);
3345 //printf("result: unputChar(%s,%s,%d,%c)\n",qPrint(expr),rest ? rest->data() : 0,pos,c);
3348 /** Returns a reference to a Define object given its name or 0 if the Define does
3351 static Define *isDefined(yyscan_t yyscanner,const QCString &name)
3353 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3356 auto findDefine = [&undef,&name](DefineMap &map)
3359 auto it = map.find(name.str());
3372 Define *def = findDefine(state->localDefines);
3373 if (def==0 && !undef)
3375 def = findDefine(state->contextDefines);
3380 static void initPredefined(yyscan_t yyscanner,const QCString &fileName)
3382 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3384 // add predefined macros
3385 const StringVector &predefList = Config_getList(PREDEFINED);
3386 for (const auto &ds : predefList)
3388 size_t i_equals=ds.find('=');
3389 size_t i_obrace=ds.find('(');
3390 size_t i_cbrace=ds.find(')');
3391 bool nonRecursive = i_equals!=std::string::npos && i_equals>0 && ds[i_equals-1]==':';
3393 if ((i_obrace==0) || (i_equals==0) || (i_equals==1 && ds[i_equals-1]==':'))
3395 continue; // no define name
3398 if (i_obrace<i_equals && i_cbrace<i_equals &&
3399 i_obrace!=std::string::npos && i_cbrace!=std::string::npos &&
3401 ) // predefined function macro definition
3403 static const reg::Ex reId(R"(\a\w*)");
3404 std::map<std::string,int> argMap;
3405 std::string args = ds.substr(i_obrace+1,i_cbrace-i_obrace-1); // part between ( and )
3406 bool hasVarArgs = args.find("...")!=std::string::npos;
3407 //printf("predefined function macro '%s'\n",ds.c_str());
3409 reg::Iterator arg_it(args,reId,0);
3410 reg::Iterator arg_end;
3411 // gather the formal arguments in a dictionary
3412 for (; arg_it!=arg_end; ++arg_it)
3414 argMap.emplace(arg_it->str(),count++);
3416 if (hasVarArgs) // add the variable argument if present
3418 argMap.emplace("__VA_ARGS__",count++);
3421 // strip definition part
3422 std::string definition;
3423 std::string in=ds.substr(i_equals+1);
3424 reg::Iterator re_it(in,reId);
3425 reg::Iterator re_end;
3427 // substitute all occurrences of formal arguments by their
3428 // corresponding markers
3429 for (; re_it!=re_end; ++re_it)
3431 const auto &match = *re_it;
3432 size_t pi = match.position();
3433 size_t l = match.length();
3434 if (pi>i) definition+=in.substr(i,pi-i);
3436 auto it = argMap.find(match.str());
3437 if (it!=argMap.end())
3439 int argIndex = it->second;
3441 marker.sprintf(" @%d ",argIndex);
3442 definition+=marker.str();
3446 definition+=match.str();
3450 definition+=in.substr(i);
3452 // add define definition to the dictionary of defines for this file
3453 std::string dname = ds.substr(0,i_obrace);
3458 def.definition = definition;
3460 def.isPredefined = TRUE;
3461 def.nonRecursive = nonRecursive;
3462 def.fileDef = state->yyFileDef;
3463 def.fileName = fileName;
3464 def.varArgs = hasVarArgs;
3465 state->contextDefines.insert(std::make_pair(def.name.str(),def));
3467 //printf("#define '%s' '%s' #nargs=%d hasVarArgs=%d\n",
3468 // qPrint(def.name),qPrint(def.definition),def.nargs,def.varArgs);
3471 else if (!ds.empty()) // predefined non-function macro definition
3473 //printf("predefined normal macro '%s'\n",ds.c_str());
3475 if (i_equals==std::string::npos) // simple define without argument
3478 def.definition = "1"; // substitute occurrences by 1 (true)
3480 else // simple define with argument
3482 int ine=static_cast<int>(i_equals) - (nonRecursive ? 1 : 0);
3483 def.name = ds.substr(0,ine);
3484 def.definition = ds.substr(i_equals+1);
3486 if (!def.name.isEmpty())
3489 def.isPredefined = TRUE;
3490 def.nonRecursive = nonRecursive;
3491 def.fileDef = state->yyFileDef;
3492 def.fileName = fileName;
3493 state->contextDefines.insert(std::make_pair(def.name.str(),def));
3499 ///////////////////////////////////////////////////////////////////////////////////////////////
3501 struct Preprocessor::Private
3507 void Preprocessor::addSearchDir(const QCString &dir)
3509 YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner);
3510 FileInfo fi(dir.str());
3511 if (fi.isDir()) state->pathList.push_back(fi.absFilePath());
3514 Preprocessor::Preprocessor() : p(std::make_unique<Private>())
3516 preYYlex_init_extra(&p->state,&p->yyscanner);
3520 Preprocessor::~Preprocessor()
3522 preYYlex_destroy(p->yyscanner);
3525 void Preprocessor::processFile(const QCString &fileName,BufStr &input,BufStr &output)
3527 // printf("Preprocessor::processFile(%s)\n",fileName);
3528 yyscan_t yyscanner = p->yyscanner;
3529 YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner);
3530 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3533 preYYset_debug(1,yyscanner);
3536 printlex(yy_flex_debug, TRUE, __FILE__, qPrint(fileName));
3537 uint orgOffset=output.curPos();
3538 //printf("##########################\n%s\n####################\n",
3541 state->macroExpansion = Config_getBool(MACRO_EXPANSION);
3542 state->expandOnlyPredef = Config_getBool(EXPAND_ONLY_PREDEF);
3544 state->curlyCount=0;
3545 state->nospaces=FALSE;
3546 state->inputBuf=&input;
3547 state->inputBufPos=0;
3548 state->outputBuf=&output;
3549 state->includeStack.clear();
3550 state->expandedDict.clear();
3551 state->contextDefines.clear();
3552 while (!state->condStack.empty()) state->condStack.pop();
3554 setFileName(yyscanner,fileName);
3556 state->inputFileDef = state->yyFileDef;
3557 //yyextra->defineManager.startContext(state->yyFileName);
3559 initPredefined(yyscanner,fileName);
3561 state->yyLineNr = 1;
3567 state->expectGuard = guessSection(fileName)==Entry::HEADER_SEC;
3568 state->guardName.resize(0);
3569 state->lastGuardName.resize(0);
3570 state->guardExpr.resize(0);
3572 preYYlex(yyscanner);
3574 while (!state->condStack.empty())
3576 const std::unique_ptr<preYY_CondCtx> &ctx = state->condStack.top();
3577 QCString sectionInfo = " ";
3578 if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",qPrint(ctx->sectionId.stripWhiteSpace()));
3579 warn(fileName,ctx->lineNr,"Conditional section%sdoes not have "
3580 "a corresponding \\endcond command within this file.",qPrint(sectionInfo));
3581 state->condStack.pop();
3583 // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829)
3584 forceEndCondSection(yyscanner);
3586 if (Debug::isFlagSet(Debug::Preprocessor))
3588 std::lock_guard<std::mutex> lock(g_debugMutex);
3589 char *orgPos=output.data()+orgOffset;
3590 char *newPos=output.data()+output.curPos();
3591 Debug::print(Debug::Preprocessor,0,"Preprocessor output of %s (size: %d bytes):\n",qPrint(fileName),newPos-orgPos);
3593 Debug::print(Debug::Preprocessor,0,"---------\n");
3594 if (!Debug::isFlagSet(Debug::NoLineNo)) Debug::print(Debug::Preprocessor,0,"00001 ");
3595 while (orgPos<newPos)
3598 if (*orgPos=='\n' && !Debug::isFlagSet(Debug::NoLineNo)) Debug::print(Debug::Preprocessor,0,"%05d ",++line);
3601 Debug::print(Debug::Preprocessor,0,"\n---------\n");
3602 if (yyextra->contextDefines.size()>0)
3604 Debug::print(Debug::Preprocessor,0,"Macros accessible in this file (%s):\n", qPrint(fileName));
3605 Debug::print(Debug::Preprocessor,0,"---------\n");
3606 for (auto &kv : yyextra->contextDefines)
3608 Debug::print(Debug::Preprocessor,0,"%s ",qPrint(kv.second.name));
3610 for (auto &kv : yyextra->localDefines)
3612 Debug::print(Debug::Preprocessor,0,"%s ",qPrint(kv.second.name));
3614 Debug::print(Debug::Preprocessor,0,"\n---------\n");
3618 Debug::print(Debug::Preprocessor,0,"No macros accessible in this file (%s).\n", qPrint(fileName));
3623 std::lock_guard<std::mutex> lock(g_updateGlobals);
3624 for (const auto &inc : state->includeRelations)
3626 if (inc->fromFileDef)
3628 inc->fromFileDef->addIncludeDependency(inc->toFileDef,inc->includeName,inc->local,inc->imported);
3630 if (inc->toFileDef && inc->fromFileDef)
3632 inc->toFileDef->addIncludedByDependency(inc->fromFileDef,inc->fromFileDef->docName(),inc->local,inc->imported);
3635 // add the macro definition for this file to the global map
3636 Doxygen::macroDefinitions.emplace(std::make_pair(state->yyFileName.str(),std::move(state->macroDefinitions)));
3639 //yyextra->defineManager.endContext();
3640 printlex(yy_flex_debug, FALSE, __FILE__, qPrint(fileName));
3641 // printf("Preprocessor::processFile(%s) finished\n",fileName);
3644 #if USE_STATE2STRING