1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2020 by Dimitri van Heesch.
4  *
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.
10  *
11  * Documents produced by Doxygen are derivative works derived from the
12  * input used in their production; they are not affected by this license.
13  *
14  */
15 %option never-interactive
16 %option prefix="preYY"
17 %option reentrant
18 %option extra-type="struct preYY_state *"
19 %top{
20 #include <stdint.h>
21 // forward declare yyscan_t to improve type safety
22 #define YY_TYPEDEF_YY_SCANNER_T
23 struct yyguts_t;
24 typedef yyguts_t *yyscan_t;
25 }
26 
27 %{
28 
29 /*
30  *      includes
31  */
32 
33 #include "doxygen.h"
34 
35 #include <stack>
36 #include <deque>
37 #include <algorithm>
38 #include <utility>
39 #include <mutex>
40 #include <thread>
41 #include <algorithm>
42 
43 #include <stdio.h>
44 #include <assert.h>
45 #include <ctype.h>
46 #include <errno.h>
47 
48 #include "qcstring.h"
49 #include "containers.h"
50 #include "pre.h"
51 #include "constexp.h"
52 #include "define.h"
53 #include "message.h"
54 #include "util.h"
55 #include "defargs.h"
56 #include "debug.h"
57 #include "bufstr.h"
58 #include "portable.h"
59 #include "bufstr.h"
60 #include "arguments.h"
61 #include "entry.h"
62 #include "condparser.h"
63 #include "config.h"
64 #include "filedef.h"
65 #include "regex.h"
66 #include "fileinfo.h"
67 
68 #define YY_NO_UNISTD_H 1
69 
70 #define USE_STATE2STRING 0
71 
72 // Toggle for some debugging info
73 //#define DBG_CTX(x) fprintf x
74 #define DBG_CTX(x) do { } while(0)
75 
76 #if USE_STATE2STRING
77 static const char *stateToString(int state);
78 #endif
79 
80 struct preYY_CondCtx
81 {
preYY_CondCtxpreYY_CondCtx82   preYY_CondCtx(int line,QCString id,bool b)
83     : lineNr(line),sectionId(id), skip(b) {}
84   int lineNr;
85   QCString sectionId;
86   bool skip;
87 };
88 
89 struct FileState
90 {
FileStateFileState91   FileState(uint size) : fileBuf(size) {}
92   int lineNr = 1;
93   int curlyCount = 0;
94   BufStr fileBuf;
95   BufStr *oldFileBuf = 0;
96   yy_size_t oldFileBufPos = 0;
97   YY_BUFFER_STATE bufState = 0;
98   QCString fileName;
99 };
100 
101 struct PreIncludeInfo
102 {
PreIncludeInfoPreIncludeInfo103   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)
105   {
106   }
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)
113 };
114 
115 /** A dictionary of managed Define objects. */
116 typedef std::map< std::string, Define > DefineMap;
117 
118 /** @brief Class that manages the defines available while
119  *  preprocessing files.
120  */
121 class DefineManager
122 {
123   private:
124     /** Local class used to hold the defines for a single file */
125     class DefinesPerFile
126     {
127       public:
128         /** Creates an empty container for defines */
DefinesPerFile(DefineManager * parent)129         DefinesPerFile(DefineManager *parent)
130           : m_parent(parent)
131         {
132         }
addInclude(std::string fileName)133         void addInclude(std::string fileName)
134         {
135           m_includedFiles.insert(fileName);
136         }
store(const DefineMap & fromMap)137         void store(const DefineMap &fromMap)
138         {
139           for (auto &kv : fromMap)
140           {
141             m_defines.emplace(kv.first,kv.second);
142           }
143           //printf("  m_defines.size()=%zu\n",m_defines.size());
144           m_stored=true;
145         }
retrieve(DefineMap & toMap)146         void retrieve(DefineMap &toMap)
147         {
148           StringSet includeStack;
149           retrieveRec(toMap,includeStack);
150         }
retrieveRec(DefineMap & toMap,StringSet & includeStack)151         void retrieveRec(DefineMap &toMap,StringSet &includeStack)
152         {
153           //printf("  retrieveRec #includedFiles=%zu\n",m_includedFiles.size());
154           for (auto incFile : m_includedFiles)
155           {
156             DefinesPerFile *dpf = m_parent->find(incFile);
157             if (dpf && includeStack.find(incFile)==includeStack.end())
158             {
159               includeStack.insert(incFile);
160               dpf->retrieveRec(toMap,includeStack);
161               //printf("  retrieveRec: processing include %s: #toMap=%zu\n",qPrint(incFile),toMap.size());
162             }
163           }
164           for (auto &kv : m_defines)
165           {
166             toMap.emplace(kv.first,kv.second);
167           }
168         }
stored()169         bool stored() const { return m_stored; }
170       private:
171         DefineManager *m_parent;
172         DefineMap m_defines;
173         StringSet m_includedFiles;
174         bool m_stored = false;
175     };
176 
177     friend class DefinesPerFile;
178   public:
179 
addInclude(std::string fromFileName,std::string toFileName)180     void addInclude(std::string fromFileName,std::string toFileName)
181     {
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())
185       {
186         it = m_fileMap.emplace(fromFileName,std::make_unique<DefinesPerFile>(this)).first;
187       }
188       auto &dpf = it->second;
189       dpf->addInclude(toFileName);
190     }
191 
store(std::string fileName,const DefineMap & fromMap)192     void store(std::string fileName,const DefineMap &fromMap)
193     {
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())
197       {
198         it = m_fileMap.emplace(fileName,std::make_unique<DefinesPerFile>(this)).first;
199       }
200       it->second->store(fromMap);
201     }
202 
retrieve(std::string fileName,DefineMap & toMap)203     void retrieve(std::string fileName,DefineMap &toMap)
204     {
205       auto it = m_fileMap.find(fileName);
206       if (it!=m_fileMap.end())
207       {
208         auto &dpf = it->second;
209         dpf->retrieve(toMap);
210       }
211       //printf("DefineManager::retrieve(%s,#=%zu)\n",fileName.c_str(),toMap.size());
212     }
213 
alreadyProcessed(std::string fileName)214     bool alreadyProcessed(std::string fileName) const
215     {
216       auto it = m_fileMap.find(fileName);
217       if (it!=m_fileMap.end())
218       {
219         return it->second->stored();
220       }
221       return false;
222     }
223 
224   private:
225     /** Helper function to return the DefinesPerFile object for a given file name. */
find(std::string fileName)226     DefinesPerFile *find(std::string fileName) const
227     {
228       auto it = m_fileMap.find(fileName);
229       return it!=m_fileMap.end() ? it->second.get() : nullptr;
230     }
231 
232     std::unordered_map< std::string, std::unique_ptr<DefinesPerFile> > m_fileMap;
233 };
234 
235 
236 /* -----------------------------------------------------------------
237  *
238  *      global state
239  */
240 static std::mutex            g_debugMutex;
241 static std::mutex            g_globalDefineMutex;
242 static std::mutex            g_updateGlobals;
243 static DefineManager         g_defineManager;
244 
245 
246 /* -----------------------------------------------------------------
247  *
248  *      scanner's state
249  */
250 
251 struct preYY_state
252 {
253   int                yyLineNr       = 1;
254   int                yyMLines       = 1;
255   int                yyColNr        = 1;
256   QCString           fileName;
257   FileDef           *yyFileDef      = 0;
258   FileDef           *inputFileDef   = 0;
259   int                ifcount        = 0;
260   int                defArgs        = -1;
261   QCString           defName;
262   QCString           defText;
263   QCString           defLitText;
264   QCString           defArgsStr;
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;
273   int                roundCount     = 0;
274   bool               quoteArg       = false;
275   bool               idStart        = false;
276   int                findDefArgContext = 0;
277   bool               expectGuard    = false;
278   QCString           guardName;
279   QCString           lastGuardName;
280   QCString           incName;
281   QCString           guardExpr;
282   int                curlyCount     = 0;
283   bool               nospaces       = false; // add extra spaces during macro expansion
284   int                javaBlock      = 0;
285 
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;
292   QCString           blockName;
293   int                condCtx        = 0;
294   bool               skip           = false;
295   bool               insideCS       = false; // C# has simpler preprocessor
296   bool               insideFtn      = false;
297   bool               isSource       = false;
298 
299   yy_size_t          fenceSize      = 0;
300   bool               ccomment       = false;
301   QCString           delimiter;
302   bool               isSpecialComment = false;
303   StringVector                             pathList;
304   IntMap                                   argMap;
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;
315 };
316 
317 // stateless functions
318 static QCString escapeAt(const QCString &text);
319 static QCString extractTrailingComment(const QCString &s);
320 static char resolveTrigraph(char c);
321 
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 &sectId);
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);
343 
344 /* ----------------------------------------------------------------- */
345 
346 #undef  YY_INPUT
347 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
348 
349 // otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
getLexerFILE()350 static inline const char *getLexerFILE() {return __FILE__;}
351 #include "doxygen_lex.h"
352 
353 /* ----------------------------------------------------------------- */
354 
355 %}
356 
357 IDSTART [a-z_A-Z\x80-\xFF]
358 ID      {IDSTART}[a-z_A-Z0-9\x80-\xFF]*
359 B       [ \t]
360 Bopt    {B}*
361 BN      [ \t\r\n]
362 RAWBEGIN  (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
363 RAWEND    ")"[^ \t\(\)\\]{0,16}\"
364 CHARLIT   (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
365 
366   // C start comment
367 CCS   "/\*"
368   // C end comment
369 CCE   "*\/"
370   // Cpp comment
371 CPPC  "/\/"
372   // optional characters after import
373 ENDIMPORTopt [^\\\n]*
374   // Optional white space
375 WSopt [ \t\r]*
376 
377 %option noyywrap
378 
379 %x      Start
380 %x      Command
381 %x      SkipCommand
382 %x      SkipLine
383 %x      SkipString
384 %x      CopyLine
385 %x      LexCopyLine
386 %x      CopyString
387 %x      CopyStringCs
388 %x      CopyStringFtn
389 %x      CopyStringFtnDouble
390 %x      CopyRawString
391 %x      Include
392 %x      IncludeID
393 %x      EndImport
394 %x      DefName
395 %x      DefineArg
396 %x      DefineText
397 %x      SkipCPPBlock
398 %x      SkipCComment
399 %x      ArgCopyCComment
400 %x      CopyCComment
401 %x      SkipVerbatim
402 %x      SkipCPPComment
403 %x      JavaDocVerbatimCode
404 %x      RemoveCComment
405 %x      RemoveCPPComment
406 %x      Guard
407 %x      DefinedExpr1
408 %x      DefinedExpr2
409 %x      SkipDoubleQuote
410 %x      SkipSingleQuote
411 %x      UndefName
412 %x      IgnoreLine
413 %x      FindDefineArgs
414 %x      ReadString
415 %x      CondLineC
416 %x      CondLineCpp
417 %x      SkipCond
418 
419 %%
420 
421 <*>\x06
422 <*>\x00
423 <*>\r
424 <*>"??"[=/'()!<>-]                      { // Trigraph
425                                           unput(resolveTrigraph(yytext[2]));
426                                         }
427 <Start>^{B}*"#"                         {
428                                           yyextra->yyColNr+=(int)yyleng;
429                                           yyextra->yyMLines=0;
430                                           yyextra->potentialDefine=yytext;
431                                           BEGIN(Command);
432                                         }
433 <Start>^("%top{"|"%{")                  {
434                                           if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt_Lex) REJECT
435                                           outputArray(yyscanner,yytext,yyleng);
436                                           BEGIN(LexCopyLine);
437                                         }
438 <Start>^{Bopt}/[^#]                     {
439                                           outputArray(yyscanner,yytext,yyleng);
440                                           BEGIN(CopyLine);
441                                         }
442 <Start>^{B}*[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]+{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors?
443                                           int i;
444                                           for (i=(int)yyleng-1;i>=0;i--)
445                                           {
446                                             unput(yytext[i]);
447                                           }
448                                           BEGIN(CopyLine);
449                                         }
450 <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
451 <Start>^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\)\n]*")"{B}*\n { // function like macro
452                                           bool skipFuncMacros = Config_getBool(SKIP_FUNCTION_MACROS);
453                                           QCString name(yytext);
454                                           int pos = name.find('(');
455                                           if (pos<0) pos=0; // should never happen
456                                           name=name.left(pos).stripWhiteSpace();
457 
458                                           Define *def=0;
459                                           if (skipFuncMacros && !yyextra->insideFtn &&
460                                               name!="Q_PROPERTY" &&
461                                               !(
462                                                  (yyextra->includeStack.empty() || yyextra->curlyCount>0) &&
463                                                  yyextra->macroExpansion &&
464                                                  (def=isDefined(yyscanner,name)) &&
465                                                  /*macroIsAccessible(def) &&*/
466                                                  (!yyextra->expandOnlyPredef || def->isPredefined)
467                                                )
468                                              )
469                                           {
470                                             outputChar(yyscanner,'\n');
471                                             yyextra->yyLineNr++;
472                                           }
473                                           else // don't skip
474                                           {
475                                             int i;
476                                             for (i=(int)yyleng-1;i>=0;i--)
477                                             {
478                                               unput(yytext[i]);
479                                             }
480                                             BEGIN(CopyLine);
481                                           }
482                                         }
483 <CopyLine,LexCopyLine>"extern"{BN}*"\""[^\"]+"\""{BN}*("{")?  {
484                                           QCString text=yytext;
485                                           yyextra->yyLineNr+=text.contains('\n');
486                                           outputArray(yyscanner,yytext,yyleng);
487                                         }
488 <CopyLine,LexCopyLine>{RAWBEGIN}        {
489                                           yyextra->delimiter = yytext+2;
490                                           yyextra->delimiter=yyextra->delimiter.left(yyextra->delimiter.length()-1);
491                                           outputArray(yyscanner,yytext,yyleng);
492                                           BEGIN(CopyRawString);
493                                         }
494 <CopyLine,LexCopyLine>"{"               { // count brackets inside the main file
495                                           if (yyextra->includeStack.empty())
496                                           {
497                                             yyextra->curlyCount++;
498                                           }
499                                           outputChar(yyscanner,*yytext);
500                                         }
501 <LexCopyLine>^"%}"                      {
502                                           outputArray(yyscanner,yytext,yyleng);
503                                         }
504 <CopyLine,LexCopyLine>"}"               { // count brackets inside the main file
505                                           if (yyextra->includeStack.empty() && yyextra->curlyCount>0)
506                                           {
507                                             yyextra->curlyCount--;
508                                           }
509                                           outputChar(yyscanner,*yytext);
510                                         }
511 <CopyLine,LexCopyLine>"'"\\[0-7]{1,3}"'" {
512                                           outputArray(yyscanner,yytext,yyleng);
513                                         }
514 <CopyLine,LexCopyLine>"'"\\."'"         {
515                                           outputArray(yyscanner,yytext,yyleng);
516                                         }
517 <CopyLine,LexCopyLine>"'"."'"           {
518                                           outputArray(yyscanner,yytext,yyleng);
519                                         }
520 <CopyLine,LexCopyLine>@\"               {
521                                           if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt_CSharp) REJECT;
522                                           outputArray(yyscanner,yytext,yyleng);
523                                           BEGIN( CopyStringCs );
524                                         }
525 <CopyLine,LexCopyLine>\"                {
526                                           outputChar(yyscanner,*yytext);
527                                           if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt_Fortran)
528                                           {
529                                             BEGIN( CopyString );
530                                           }
531                                           else
532                                           {
533                                             BEGIN( CopyStringFtnDouble );
534                                           }
535                                         }
536 <CopyLine,LexCopyLine>\'                {
537                                           if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt_Fortran) REJECT;
538                                           outputChar(yyscanner,*yytext);
539                                           BEGIN( CopyStringFtn );
540                                         }
541 <CopyString>[^\"\\\r\n]+                {
542                                           outputArray(yyscanner,yytext,yyleng);
543                                         }
544 <CopyStringCs>[^\"\r\n]+                {
545                                           outputArray(yyscanner,yytext,yyleng);
546                                         }
547 <CopyString>\\.                         {
548                                           outputArray(yyscanner,yytext,yyleng);
549                                         }
550 <CopyString,CopyStringCs>\"             {
551                                           outputChar(yyscanner,*yytext);
552                                           BEGIN( CopyLine );
553                                         }
554 <CopyStringFtnDouble>[^\"\\\r\n]+       {
555                                           outputArray(yyscanner,yytext,yyleng);
556                                         }
557 <CopyStringFtnDouble>\\.                {
558                                           outputArray(yyscanner,yytext,yyleng);
559                                         }
560 <CopyStringFtnDouble>\"                 {
561                                           outputChar(yyscanner,*yytext);
562                                           BEGIN( CopyLine );
563                                         }
564 <CopyStringFtn>[^\'\\\r\n]+             {
565                                           outputArray(yyscanner,yytext,yyleng);
566                                         }
567 <CopyStringFtn>\\.                      {
568                                           outputArray(yyscanner,yytext,yyleng);
569                                         }
570 <CopyStringFtn>\'                       {
571                                           outputChar(yyscanner,*yytext);
572                                           BEGIN( CopyLine );
573                                         }
574 <CopyRawString>{RAWEND}                 {
575                                           outputArray(yyscanner,yytext,yyleng);
576                                           QCString delimiter = yytext+1;
577                                           delimiter=delimiter.left(delimiter.length()-1);
578                                           if (delimiter==yyextra->delimiter)
579                                           {
580                                             BEGIN( CopyLine );
581                                           }
582                                         }
583 <CopyRawString>[^)]+                    {
584                                           outputArray(yyscanner,yytext,yyleng);
585                                         }
586 <CopyRawString>.                        {
587                                           outputChar(yyscanner,*yytext);
588                                         }
589 <CopyLine,LexCopyLine>{ID}/{BN}{0,80}"("        {
590                                           yyextra->expectGuard = FALSE;
591                                           Define *def=0;
592                                           //def=yyextra->globalDefineDict->find(yytext);
593                                           //def=isDefined(yyscanner,yytext);
594                                           //printf("Search for define %s found=%d yyextra->includeStack.empty()=%d "
595                                           //       "yyextra->curlyCount=%d yyextra->macroExpansion=%d yyextra->expandOnlyPredef=%d "
596                                           //     "isPreDefined=%d\n",yytext,def ? 1 : 0,
597                                           //     yyextra->includeStack.empty(),yyextra->curlyCount,yyextra->macroExpansion,yyextra->expandOnlyPredef,
598                                           //     def ? def->isPredefined : -1
599                                           //    );
600                                           if ((yyextra->includeStack.empty() || yyextra->curlyCount>0) &&
601                                               yyextra->macroExpansion &&
602                                               (def=isDefined(yyscanner,yytext)) &&
603                                               /*(def->isPredefined || macroIsAccessible(def)) && */
604                                               (!yyextra->expandOnlyPredef || def->isPredefined)
605                                              )
606                                           {
607                                             //printf("Found it! #args=%d\n",def->nargs);
608                                             yyextra->roundCount=0;
609                                             yyextra->defArgsStr=yytext;
610                                             if (def->nargs==-1) // no function macro
611                                             {
612                                               QCString result = def->isPredefined ? def->definition : expandMacro(yyscanner,yyextra->defArgsStr);
613                                               outputString(yyscanner,result);
614                                             }
615                                             else // zero or more arguments
616                                             {
617                                               yyextra->findDefArgContext = CopyLine;
618                                               BEGIN(FindDefineArgs);
619                                             }
620                                           }
621                                           else
622                                           {
623                                             outputArray(yyscanner,yytext,yyleng);
624                                           }
625                                         }
626 <CopyLine,LexCopyLine>{ID}              {
627                                           Define *def=0;
628                                           if ((yyextra->includeStack.empty() || yyextra->curlyCount>0) &&
629                                               yyextra->macroExpansion &&
630                                               (def=isDefined(yyscanner,yytext)) &&
631                                               def->nargs==-1 &&
632                                               /*(def->isPredefined || macroIsAccessible(def)) &&*/
633                                               (!yyextra->expandOnlyPredef || def->isPredefined)
634                                              )
635                                           {
636                                             QCString result=def->isPredefined ? def->definition : expandMacro(yyscanner,yytext);
637                                             outputString(yyscanner,result);
638                                           }
639                                           else
640                                           {
641                                             outputArray(yyscanner,yytext,yyleng);
642                                           }
643                                         }
644 <CopyLine,LexCopyLine>"\\"\r?/\n        { // strip line continuation characters
645                                           if (getLanguageFromFileName(yyextra->fileName)==SrcLangExt_Fortran) outputChar(yyscanner,*yytext);
646                                         }
647 <CopyLine,LexCopyLine>\\.               {
648                                           outputArray(yyscanner,yytext,(int)yyleng);
649                                         }
650 <CopyLine,LexCopyLine>.                 {
651                                           outputChar(yyscanner,*yytext);
652                                         }
653 <CopyLine,LexCopyLine>\n                {
654                                           outputChar(yyscanner,'\n');
655                                           BEGIN(Start);
656                                           yyextra->yyLineNr++;
657                                           yyextra->yyColNr=1;
658                                         }
659 <FindDefineArgs>"("                     {
660                                           yyextra->defArgsStr+='(';
661                                           yyextra->roundCount++;
662                                         }
663 <FindDefineArgs>")"                     {
664                                           yyextra->defArgsStr+=')';
665                                           yyextra->roundCount--;
666                                           if (yyextra->roundCount==0)
667                                           {
668                                             QCString result=expandMacro(yyscanner,yyextra->defArgsStr);
669                                             //printf("yyextra->defArgsStr='%s'->'%s'\n",qPrint(yyextra->defArgsStr),qPrint(result));
670                                             if (yyextra->findDefArgContext==CopyLine)
671                                             {
672                                               outputString(yyscanner,result);
673                                               BEGIN(yyextra->findDefArgContext);
674                                             }
675                                             else // yyextra->findDefArgContext==IncludeID
676                                             {
677                                               readIncludeFile(yyscanner,result);
678                                               yyextra->nospaces=FALSE;
679                                               BEGIN(Start);
680                                             }
681                                           }
682                                         }
683   /*
684 <FindDefineArgs>")"{B}*"("              {
685                                           yyextra->defArgsStr+=yytext;
686                                         }
687   */
688 <FindDefineArgs>{CHARLIT}               {
689                                           yyextra->defArgsStr+=yytext;
690                                         }
691 <FindDefineArgs>{CCS}[*]?                {
692                                           yyextra->defArgsStr+=yytext;
693                                           BEGIN(ArgCopyCComment);
694                                         }
695 <FindDefineArgs>\"                      {
696                                           yyextra->defArgsStr+=*yytext;
697                                           BEGIN(ReadString);
698                                         }
699 <FindDefineArgs>'                       {
700                                           if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt_Fortran) REJECT;
701                                           yyextra->defArgsStr+=*yytext;
702                                           BEGIN(ReadString);
703                                         }
704 <FindDefineArgs>\n                      {
705                                           yyextra->defArgsStr+=' ';
706                                           yyextra->yyLineNr++;
707                                           outputChar(yyscanner,'\n');
708                                         }
709 <FindDefineArgs>"@"                     {
710                                           yyextra->defArgsStr+="@@";
711                                         }
712 <FindDefineArgs>.                       {
713                                           yyextra->defArgsStr+=*yytext;
714                                         }
715 <ArgCopyCComment>[^*\n]+                {
716                                           yyextra->defArgsStr+=yytext;
717                                         }
718 <ArgCopyCComment>{CCE}                  {
719                                           yyextra->defArgsStr+=yytext;
720                                           BEGIN(FindDefineArgs);
721                                         }
722 <ArgCopyCComment>\n                     {
723                                           yyextra->defArgsStr+=' ';
724                                           yyextra->yyLineNr++;
725                                           outputChar(yyscanner,'\n');
726                                         }
727 <ArgCopyCComment>.                      {
728                                           yyextra->defArgsStr+=yytext;
729                                         }
730 <ReadString>"\""                        {
731                                           yyextra->defArgsStr+=*yytext;
732                                           BEGIN(FindDefineArgs);
733                                         }
734 <ReadString>"'"                         {
735                                           if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt_Fortran) REJECT;
736                                           yyextra->defArgsStr+=*yytext;
737                                           BEGIN(FindDefineArgs);
738                                         }
739 
740 <ReadString>{CPPC}|{CCS}                        {
741                                           yyextra->defArgsStr+=yytext;
742                                         }
743 <ReadString>\\/\r?\n                    { // line continuation
744                                         }
745 <ReadString>\\.                         {
746                                           yyextra->defArgsStr+=yytext;
747                                         }
748 <ReadString>.                           {
749                                           yyextra->defArgsStr+=*yytext;
750                                         }
751 <Command>("include"|"import"){B}+/{ID}  {
752                                           yyextra->isImported = yytext[1]=='m';
753                                           if (yyextra->macroExpansion)
754                                             BEGIN(IncludeID);
755                                         }
756 <Command>("include"|"import"){B}*[<"]   {
757                                           yyextra->isImported = yytext[1]=='m';
758                                           char c[2];
759                                           c[0]=yytext[yyleng-1];c[1]='\0';
760                                           yyextra->incName=c;
761                                           BEGIN(Include);
762                                         }
763 <Command>("cmake")?"define"{B}+         {
764                                           yyextra->potentialDefine += substitute(yytext,"cmake","     ");
765                                           //printf("!!!DefName\n");
766                                           yyextra->yyColNr+=(int)yyleng;
767                                           BEGIN(DefName);
768                                         }
769 <Command>"ifdef"/{B}*"("                {
770                                           incrLevel(yyscanner);
771                                           yyextra->guardExpr.resize(0);
772                                           BEGIN(DefinedExpr2);
773                                         }
774 <Command>"ifdef"/{B}+                   {
775                                           //printf("Pre.l: ifdef\n");
776                                           incrLevel(yyscanner);
777                                           yyextra->guardExpr.resize(0);
778                                           BEGIN(DefinedExpr1);
779                                         }
780 <Command>"ifndef"/{B}*"("               {
781                                           incrLevel(yyscanner);
782                                           yyextra->guardExpr="! ";
783                                           BEGIN(DefinedExpr2);
784                                         }
785 <Command>"ifndef"/{B}+                  {
786                                           incrLevel(yyscanner);
787                                           yyextra->guardExpr="! ";
788                                           BEGIN(DefinedExpr1);
789                                         }
790 <Command>"if"/[ \t(!]                   {
791                                           incrLevel(yyscanner);
792                                           yyextra->guardExpr.resize(0);
793                                           BEGIN(Guard);
794                                         }
795 <Command>("elif"|"else"{B}*"if")/[ \t(!]        {
796                                           if (!otherCaseDone(yyscanner))
797                                           {
798                                             yyextra->guardExpr.resize(0);
799                                             BEGIN(Guard);
800                                           }
801                                           else
802                                           {
803                                             yyextra->ifcount=0;
804                                             BEGIN(SkipCPPBlock);
805                                           }
806                                         }
807 <Command>"else"/[^a-z_A-Z0-9\x80-\xFF]          {
808                                           if (otherCaseDone(yyscanner))
809                                           {
810                                             yyextra->ifcount=0;
811                                             BEGIN(SkipCPPBlock);
812                                           }
813                                           else
814                                           {
815                                             setCaseDone(yyscanner,TRUE);
816                                           }
817                                         }
818 <Command>"undef"{B}+                    {
819                                           BEGIN(UndefName);
820                                         }
821 <Command>("elif"|"else"{B}*"if")/[ \t(!]        {
822                                           if (!otherCaseDone(yyscanner))
823                                           {
824                                             yyextra->guardExpr.resize(0);
825                                             BEGIN(Guard);
826                                           }
827                                         }
828 <Command>"endif"/[^a-z_A-Z0-9\x80-\xFF]         {
829                                           //printf("Pre.l: #endif\n");
830                                           decrLevel(yyscanner);
831                                         }
832 <Command,IgnoreLine>\n                  {
833                                           outputChar(yyscanner,'\n');
834                                           BEGIN(Start);
835                                           yyextra->yyLineNr++;
836                                         }
837 <Command>"pragma"{B}+"once"             {
838                                           yyextra->expectGuard = FALSE;
839                                         }
840 <Command>{ID}                           { // unknown directive
841                                           BEGIN(IgnoreLine);
842                                         }
843 <IgnoreLine>\\[\r]?\n                   {
844                                           outputChar(yyscanner,'\n');
845                                           yyextra->yyLineNr++;
846                                         }
847 <IgnoreLine>.
848 <Command>.                              { yyextra->potentialDefine += yytext[0]=='\t' ? '\t' : ' ';
849                                           yyextra->yyColNr+=(int)yyleng;
850                                         }
851 <UndefName>{ID}                         {
852                                           Define *def;
853                                           if ((def=isDefined(yyscanner,yytext))
854                                               /*&& !def->isPredefined*/
855                                               && !def->nonRecursive
856                                              )
857                                           {
858                                             //printf("undefining %s\n",yytext);
859                                             def->undef=TRUE;
860                                           }
861                                           BEGIN(Start);
862                                         }
863 <Guard>\\[\r]?\n                        {
864                                           outputChar(yyscanner,'\n');
865                                           yyextra->guardExpr+=' ';
866                                           yyextra->yyLineNr++;
867                                         }
868 <Guard>"defined"/{B}*"("                {
869                                           BEGIN(DefinedExpr2);
870                                         }
871 <Guard>"defined"/{B}+                   {
872                                           BEGIN(DefinedExpr1);
873                                         }
874 <Guard>"true"/{B}|{B}*[\r]?\n           { yyextra->guardExpr+="1L"; }
875 <Guard>"false"/{B}|{B}*[\r]?\n          { yyextra->guardExpr+="0L"; }
876 <Guard>"not"/{B}                        { yyextra->guardExpr+='!'; }
877 <Guard>"not_eq"/{B}                     { yyextra->guardExpr+="!="; }
878 <Guard>"and"/{B}                        { yyextra->guardExpr+="&&"; }
879 <Guard>"or"/{B}                         { yyextra->guardExpr+="||"; }
880 <Guard>"bitand"/{B}                     { yyextra->guardExpr+="&"; }
881 <Guard>"bitor"/{B}                      { yyextra->guardExpr+="|"; }
882 <Guard>"xor"/{B}                        { yyextra->guardExpr+="^"; }
883 <Guard>"compl"/{B}                      { yyextra->guardExpr+="~"; }
884 <Guard>{ID}                             { yyextra->guardExpr+=yytext; }
885 <Guard>"@"                              { yyextra->guardExpr+="@@"; }
886 <Guard>.                                { yyextra->guardExpr+=*yytext; }
887 <Guard>\n                               {
888                                           unput(*yytext);
889                                           //printf("Guard: '%s'\n",
890                                           //    qPrint(yyextra->guardExpr));
891                                           bool guard=computeExpression(yyscanner,yyextra->guardExpr);
892                                           setCaseDone(yyscanner,guard);
893                                           if (guard)
894                                           {
895                                             BEGIN(Start);
896                                           }
897                                           else
898                                           {
899                                             yyextra->ifcount=0;
900                                             BEGIN(SkipCPPBlock);
901                                           }
902                                         }
903 <DefinedExpr1,DefinedExpr2>\\\n         { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
904 <DefinedExpr1>{ID}                      {
905                                           if (isDefined(yyscanner,yytext) || yyextra->guardName==yytext)
906                                             yyextra->guardExpr+=" 1L ";
907                                           else
908                                             yyextra->guardExpr+=" 0L ";
909                                           yyextra->lastGuardName=yytext;
910                                           BEGIN(Guard);
911                                         }
912 <DefinedExpr2>{ID}                      {
913                                           if (isDefined(yyscanner,yytext) || yyextra->guardName==yytext)
914                                             yyextra->guardExpr+=" 1L ";
915                                           else
916                                             yyextra->guardExpr+=" 0L ";
917                                           yyextra->lastGuardName=yytext;
918                                         }
919 <DefinedExpr1,DefinedExpr2>\n           { // should not happen, handle anyway
920                                           yyextra->yyLineNr++;
921                                           yyextra->ifcount=0;
922                                           BEGIN(SkipCPPBlock);
923                                         }
924 <DefinedExpr2>")"                       {
925                                           BEGIN(Guard);
926                                         }
927 <DefinedExpr1,DefinedExpr2>.
928 <SkipCPPBlock>^{B}*"#"                  { BEGIN(SkipCommand); }
929 <SkipCPPBlock>^{Bopt}/[^#]              { BEGIN(SkipLine); }
930 <SkipCPPBlock>\n                        { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
931 <SkipCPPBlock>.
932 <SkipCommand>"if"(("n")?("def"))?/[ \t(!] {
933                                           incrLevel(yyscanner);
934                                           yyextra->ifcount++;
935                                           //printf("#if... depth=%d\n",yyextra->ifcount);
936                                         }
937 <SkipCommand>"else"                     {
938                                           //printf("Else! yyextra->ifcount=%d otherCaseDone=%d\n",yyextra->ifcount,otherCaseDone());
939                                           if (yyextra->ifcount==0 && !otherCaseDone(yyscanner))
940                                           {
941                                             setCaseDone(yyscanner,TRUE);
942                                             //outputChar(yyscanner,'\n');
943                                             BEGIN(Start);
944                                           }
945                                         }
946 <SkipCommand>("elif"|"else"{B}*"if")/[ \t(!]            {
947                                           if (yyextra->ifcount==0)
948                                           {
949                                             if (!otherCaseDone(yyscanner))
950                                             {
951                                               yyextra->guardExpr.resize(0);
952                                               yyextra->lastGuardName.resize(0);
953                                               BEGIN(Guard);
954                                             }
955                                             else
956                                             {
957                                               BEGIN(SkipCPPBlock);
958                                             }
959                                           }
960                                         }
961 <SkipCommand>"endif"                    {
962                                           yyextra->expectGuard = FALSE;
963                                           decrLevel(yyscanner);
964                                           if (--yyextra->ifcount<0)
965                                           {
966                                             //outputChar(yyscanner,'\n');
967                                             BEGIN(Start);
968                                           }
969                                         }
970 <SkipCommand>\n                         {
971                                           outputChar(yyscanner,'\n');
972                                           yyextra->yyLineNr++;
973                                           BEGIN(SkipCPPBlock);
974                                         }
975 <SkipCommand>{ID}                       { // unknown directive
976                                           BEGIN(SkipLine);
977                                         }
978 <SkipCommand>.
979 <SkipLine>[^'"/\n]+
980 <SkipLine>{CHARLIT}                     { }
981 <SkipLine>\"                            {
982                                           BEGIN(SkipString);
983                                         }
984 <SkipLine>.
985 <SkipString>{CPPC}/[^\n]*                 {
986                                         }
987 <SkipLine,SkipCommand,SkipCPPBlock>{CPPC}[^\n]* {
988                                           yyextra->lastCPPContext=YY_START;
989                                           BEGIN(RemoveCPPComment);
990                                         }
991 <SkipString>{CCS}/[^\n]*                 {
992                                         }
993 <SkipLine,SkipCommand,SkipCPPBlock>{CCS}/[^\n]* {
994                                           yyextra->lastCContext=YY_START;
995                                           BEGIN(RemoveCComment);
996                                         }
997 <SkipLine>\n                            {
998                                           outputChar(yyscanner,'\n');
999                                           yyextra->yyLineNr++;
1000                                           BEGIN(SkipCPPBlock);
1001                                         }
1002 <SkipString>[^"\\\n]+                   { }
1003 <SkipString>\\.                         { }
1004 <SkipString>\"                          {
1005                                           BEGIN(SkipLine);
1006                                         }
1007 <SkipString>.                           { }
1008 <IncludeID>{ID}{Bopt}/"("                       {
1009                                           yyextra->nospaces=TRUE;
1010                                           yyextra->roundCount=0;
1011                                           yyextra->defArgsStr=yytext;
1012                                           yyextra->findDefArgContext = IncludeID;
1013                                           BEGIN(FindDefineArgs);
1014                                         }
1015 <IncludeID>{ID}                         {
1016                                           yyextra->nospaces=TRUE;
1017                                           readIncludeFile(yyscanner,expandMacro(yyscanner,yytext));
1018                                           BEGIN(Start);
1019                                         }
1020 <Include>[^\">\n]+[\">]                 {
1021                                           yyextra->incName+=yytext;
1022                                           readIncludeFile(yyscanner,yyextra->incName);
1023                                           if (yyextra->isImported)
1024                                           {
1025                                             BEGIN(EndImport);
1026                                           }
1027                                           else
1028                                           {
1029                                             BEGIN(Start);
1030                                           }
1031                                         }
1032 <EndImport>{ENDIMPORTopt}/\n                    {
1033                                           BEGIN(Start);
1034                                         }
1035 <EndImport>\\[\r]?"\n"                  {
1036                                           outputChar(yyscanner,'\n');
1037                                           yyextra->yyLineNr++;
1038                                         }
1039 <EndImport>.                            {
1040                                         }
1041 <DefName>{ID}/("\\\n")*"("              { // define with argument
1042                                           //printf("Define() '%s'\n",yytext);
1043                                           yyextra->argMap.clear();
1044                                           yyextra->defArgs = 0;
1045                                           yyextra->defArgsStr.resize(0);
1046                                           yyextra->defText.resize(0);
1047                                           yyextra->defLitText.resize(0);
1048                                           yyextra->defName = yytext;
1049                                           yyextra->defVarArgs = FALSE;
1050                                           yyextra->defExtraSpacing.resize(0);
1051                                           yyextra->defContinue = false;
1052                                           BEGIN(DefineArg);
1053                                         }
1054 <DefName>{ID}{B}+"1"/[ \r\t\n]          { // special case: define with 1 -> can be "guard"
1055                                           //printf("Define '%s'\n",yytext);
1056                                           yyextra->argMap.clear();
1057                                           yyextra->defArgs = -1;
1058                                           yyextra->defArgsStr.resize(0);
1059                                           yyextra->defName = QCString(yytext).left(yyleng-1).stripWhiteSpace();
1060                                           yyextra->defVarArgs = FALSE;
1061                                           //printf("Guard check: %s!=%s || %d\n",
1062                                           //    qPrint(yyextra->defName),qPrint(yyextra->lastGuardName),yyextra->expectGuard);
1063                                           if (yyextra->curlyCount>0 || yyextra->defName!=yyextra->lastGuardName || !yyextra->expectGuard)
1064                                           { // define may appear in the output
1065                                             QCString def = yyextra->potentialDefine +
1066                                                            yyextra->defName         ;
1067                                             outputString(yyscanner,def);
1068                                             outputSpaces(yyscanner,yytext+yyextra->defName.length());
1069                                             yyextra->quoteArg=FALSE;
1070                                             yyextra->insideComment=FALSE;
1071                                             yyextra->lastGuardName.resize(0);
1072                                             yyextra->defText="1";
1073                                             yyextra->defLitText="1";
1074                                             BEGIN(DefineText);
1075                                           }
1076                                           else // define is a guard => hide
1077                                           {
1078                                             //printf("Found a guard %s\n",yytext);
1079                                             yyextra->defText.resize(0);
1080                                             yyextra->defLitText.resize(0);
1081                                             BEGIN(Start);
1082                                           }
1083                                           yyextra->expectGuard=FALSE;
1084                                         }
1085 <DefName>{ID}/{B}*"\n"                  { // empty define
1086                                           yyextra->argMap.clear();
1087                                           yyextra->defArgs = -1;
1088                                           yyextra->defName = yytext;
1089                                           yyextra->defArgsStr.resize(0);
1090                                           yyextra->defText.resize(0);
1091                                           yyextra->defLitText.resize(0);
1092                                           yyextra->defVarArgs = FALSE;
1093                                           //printf("Guard check: %s!=%s || %d\n",
1094                                           //    qPrint(yyextra->defName),qPrint(yyextra->lastGuardName),yyextra->expectGuard);
1095                                           if (yyextra->curlyCount>0 || yyextra->defName!=yyextra->lastGuardName || !yyextra->expectGuard)
1096                                           { // define may appear in the output
1097                                             QCString def = yyextra->potentialDefine + yyextra->defName;
1098                                             outputString(yyscanner,def);
1099                                             yyextra->quoteArg=FALSE;
1100                                             yyextra->insideComment=FALSE;
1101                                             if (yyextra->insideCS) yyextra->defText="1"; // for C#, use "1" as define text
1102                                             BEGIN(DefineText);
1103                                           }
1104                                           else // define is a guard => hide
1105                                           {
1106                                             //printf("Found a guard %s\n",yytext);
1107                                             yyextra->guardName = yytext;
1108                                             yyextra->lastGuardName.resize(0);
1109                                             BEGIN(Start);
1110                                           }
1111                                           yyextra->expectGuard=FALSE;
1112                                         }
1113 <DefName>{ID}/{B}*                      { // define with content
1114                                           //printf("Define '%s'\n",yytext);
1115                                           yyextra->argMap.clear();
1116                                           yyextra->defArgs = -1;
1117                                           yyextra->defArgsStr.resize(0);
1118                                           yyextra->defText.resize(0);
1119                                           yyextra->defLitText.resize(0);
1120                                           yyextra->defName = yytext;
1121                                           yyextra->defVarArgs = FALSE;
1122                                           QCString def = yyextra->potentialDefine +
1123                                                          yyextra->defName         +
1124                                                          yyextra->defArgsStr      ;
1125                                           outputString(yyscanner,def);
1126                                           yyextra->quoteArg=FALSE;
1127                                           yyextra->insideComment=FALSE;
1128                                           BEGIN(DefineText);
1129                                         }
1130 <DefineArg>"\\\n"                       {
1131                                           yyextra->defExtraSpacing+="\n";
1132                                           yyextra->defContinue = true;
1133                                           yyextra->yyLineNr++;
1134                                         }
1135 <DefineArg>{B}*                         { yyextra->defExtraSpacing+=yytext; }
1136 <DefineArg>","{B}*                      { yyextra->defArgsStr+=yytext; }
1137 <DefineArg>"("{B}*                      { yyextra->defArgsStr+=yytext; }
1138 <DefineArg>{B}*")"{B}*                  {
1139                                           extraSpacing(yyscanner);
1140                                           yyextra->defArgsStr+=yytext;
1141                                           QCString def = yyextra->potentialDefine +
1142                                                          yyextra->defName         +
1143                                                          yyextra->defArgsStr      +
1144                                                          yyextra->defExtraSpacing ;
1145                                           outputString(yyscanner,def);
1146                                           yyextra->quoteArg=FALSE;
1147                                           yyextra->insideComment=FALSE;
1148                                           BEGIN(DefineText);
1149                                         }
1150 <DefineArg>"..."                        { // Variadic macro
1151                                           yyextra->defVarArgs = TRUE;
1152                                           yyextra->defArgsStr+=yytext;
1153                                           yyextra->argMap.emplace(std::string("__VA_ARGS__"),yyextra->defArgs);
1154                                           yyextra->defArgs++;
1155                                         }
1156 <DefineArg>{ID}{B}*("..."?)             {
1157                                           //printf("Define addArg(%s)\n",yytext);
1158                                           QCString argName=yytext;
1159                                           yyextra->defVarArgs = yytext[yyleng-1]=='.';
1160                                           if (yyextra->defVarArgs) // strip ellipsis
1161                                           {
1162                                             argName=argName.left(argName.length()-3);
1163                                           }
1164                                           argName = argName.stripWhiteSpace();
1165                                           yyextra->defArgsStr+=yytext;
1166                                           yyextra->argMap.emplace(toStdString(argName),yyextra->defArgs);
1167                                           yyextra->defArgs++;
1168                                           extraSpacing(yyscanner);
1169                                         }
1170   /*
1171 <DefineText>"/ **"|"/ *!"                       {
1172                                           yyextra->defText+=yytext;
1173                                           yyextra->defLitText+=yytext;
1174                                           yyextra->insideComment=TRUE;
1175                                         }
1176 <DefineText>"* /"                       {
1177                                           yyextra->defText+=yytext;
1178                                           yyextra->defLitText+=yytext;
1179                                           yyextra->insideComment=FALSE;
1180                                         }
1181   */
1182 <DefineText>{CCS}[!*]?                  {
1183                                           yyextra->defText+=yytext;
1184                                           yyextra->defLitText+=yytext;
1185                                           yyextra->lastCContext=YY_START;
1186                                           yyextra->commentCount=1;
1187                                           BEGIN(CopyCComment);
1188                                         }
1189 <DefineText>{CPPC}[!/]?                 {
1190                                           outputArray(yyscanner,yytext,yyleng);
1191                                           yyextra->lastCPPContext=YY_START;
1192                                           yyextra->defLitText+=' ';
1193                                           BEGIN(SkipCPPComment);
1194                                         }
1195 <SkipCComment>[/]?{CCE}                 {
1196                                           if (yytext[0]=='/') outputChar(yyscanner,'/');
1197                                           outputChar(yyscanner,'*');outputChar(yyscanner,'/');
1198                                           if (--yyextra->commentCount<=0)
1199                                           {
1200                                             if (yyextra->lastCContext==Start)
1201                                               // small hack to make sure that ^... rule will
1202                                               // match when going to Start... Example: "/*...*/ some stuff..."
1203                                             {
1204                                               YY_CURRENT_BUFFER->yy_at_bol=1;
1205                                             }
1206                                             BEGIN(yyextra->lastCContext);
1207                                           }
1208                                         }
1209 <SkipCComment>{CPPC}("/")*              {
1210                                           outputArray(yyscanner,yytext,yyleng);
1211                                         }
1212 <SkipCComment>{CCS}                     {
1213                                           outputChar(yyscanner,'/');outputChar(yyscanner,'*');
1214                                           //yyextra->commentCount++;
1215                                         }
1216 <SkipCComment>[\\@][\\@]("f{"|"f$"|"f[""f(") {
1217                                           outputArray(yyscanner,yytext,yyleng);
1218                                         }
1219 <SkipCComment>^({B}*"*"+)?{B}{0,3}"~~~"[~]*   {
1220                                           bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1221                                           if (!markdownSupport || !yyextra->isSpecialComment)
1222                                           {
1223                                             REJECT;
1224                                           }
1225                                           else
1226                                           {
1227                                             outputArray(yyscanner,yytext,yyleng);
1228                                             yyextra->fenceSize=(int)yyleng;
1229                                             BEGIN(SkipVerbatim);
1230                                           }
1231                                         }
1232 <SkipCComment>^({B}*"*"+)?{B}{0,3}"```"[`]*            {
1233                                           bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1234                                           if (!markdownSupport || !yyextra->isSpecialComment)
1235                                           {
1236                                             REJECT;
1237                                           }
1238                                           else
1239                                           {
1240                                             outputArray(yyscanner,yytext,yyleng);
1241                                             yyextra->fenceSize=(int)yyleng;
1242                                             BEGIN(SkipVerbatim);
1243                                           }
1244                                         }
1245 <SkipCComment>[\\@][\\@]("verbatim"|"iliteral"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+ {
1246                                           outputArray(yyscanner,yytext,yyleng);
1247                                           yyextra->yyLineNr+=QCString(yytext).contains('\n');
1248                                         }
1249 <SkipCComment>[\\@]("verbatim"|"iliteral"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly"|"dot"|"code"("{"[^}]*"}")?){BN}+      {
1250                                           outputArray(yyscanner,yytext,yyleng);
1251                                           yyextra->yyLineNr+=QCString(yytext).contains('\n');
1252                                           yyextra->fenceSize=0;
1253                                           if (yytext[1]=='f')
1254                                           {
1255                                             yyextra->blockName="f";
1256                                           }
1257                                           else
1258                                           {
1259                                             QCString bn=&yytext[1];
1260                                             int i = bn.find('{'); // for \code{.c}
1261                                             if (i!=-1) bn=bn.left(i);
1262                                             yyextra->blockName=bn.stripWhiteSpace();
1263                                           }
1264                                           BEGIN(SkipVerbatim);
1265                                         }
1266 <SkipCond>[\\@][\\@]"cond"[ \t]+        {}// escaped cond command
1267 <SkipCond>[\\@]"cond"[ \t]+             { // cond command in a skipped cond section, this section has to be skipped as well
1268                                           // but has to be recorded to match the endcond command
1269                                           startCondSection(yyscanner," ");
1270                                         }
1271 <SkipCComment>"{"[ \t]*"@code"/[ \t\n]  {
1272                                           outputArray(yyscanner,"@iliteral{code}",15);
1273                                           yyextra->javaBlock=1;
1274                                           BEGIN(JavaDocVerbatimCode);
1275                                         }
1276 <SkipCComment>"{"[ \t]*"@literal"/[ \t\n]  {
1277                                           outputArray(yyscanner,"@iliteral",9);
1278                                           yyextra->javaBlock=1;
1279                                           BEGIN(JavaDocVerbatimCode);
1280                                         }
1281 <SkipCComment,SkipCPPComment>[\\@][\\@]"cond"[ \t]+ { // escaped @cond
1282                                           outputArray(yyscanner,yytext,yyleng);
1283                                         }
1284 <SkipCPPComment>[\\@]"cond"[ \t]+       { // conditional section
1285                                           yyextra->ccomment=TRUE;
1286                                           yyextra->condCtx=YY_START;
1287                                           BEGIN(CondLineCpp);
1288                                         }
1289 <SkipCComment>[\\@]"cond"[ \t]+ { // conditional section
1290                                           yyextra->ccomment=FALSE;
1291                                           yyextra->condCtx=YY_START;
1292                                           BEGIN(CondLineC);
1293                                         }
1294 <CondLineC,CondLineCpp>[!()&| \ta-z_A-Z0-9\x80-\xFF.\-]+      {
1295                                           startCondSection(yyscanner,yytext);
1296                                           if (yyextra->skip)
1297                                           {
1298                                             if (YY_START==CondLineC)
1299                                             {
1300                                               // end C comment
1301                                               outputArray(yyscanner,"*/",2);
1302                                               yyextra->ccomment=TRUE;
1303                                             }
1304                                             else
1305                                             {
1306                                               yyextra->ccomment=FALSE;
1307                                             }
1308                                             BEGIN(SkipCond);
1309                                           }
1310                                           else
1311                                           {
1312                                             BEGIN(yyextra->condCtx);
1313                                           }
1314                                         }
1315 <CondLineC,CondLineCpp>.                { // non-guard character
1316                                           unput(*yytext);
1317                                           startCondSection(yyscanner," ");
1318                                           if (yyextra->skip)
1319                                           {
1320                                             if (YY_START==CondLineC)
1321                                             {
1322                                               // end C comment
1323                                               outputArray(yyscanner,"*/",2);
1324                                               yyextra->ccomment=TRUE;
1325                                             }
1326                                             else
1327                                             {
1328                                               yyextra->ccomment=FALSE;
1329                                             }
1330                                             BEGIN(SkipCond);
1331                                           }
1332                                           else
1333                                           {
1334                                             BEGIN(yyextra->condCtx);
1335                                           }
1336                                         }
1337 <SkipCComment,SkipCPPComment>[\\@]"cond"{WSopt}/\n { // no guard
1338                                           if (YY_START==SkipCComment)
1339                                           {
1340                                             yyextra->ccomment=TRUE;
1341                                             // end C comment
1342                                             outputArray(yyscanner,"*/",2);
1343                                           }
1344                                           else
1345                                           {
1346                                             yyextra->ccomment=FALSE;
1347                                           }
1348                                           yyextra->condCtx=YY_START;
1349                                           startCondSection(yyscanner," ");
1350                                           BEGIN(SkipCond);
1351                                         }
1352 <SkipCond>\n                            { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
1353 <SkipCond>.                             { }
1354 <SkipCond>[^\/\!*\\@\n]+                { }
1355 <SkipCond>{CPPC}[/!]                      { yyextra->ccomment=FALSE; }
1356 <SkipCond>{CCS}[*!]                      { yyextra->ccomment=TRUE; }
1357 <SkipCond,SkipCComment,SkipCPPComment>[\\@][\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1358                                           if (!yyextra->skip)
1359                                           {
1360                                             outputArray(yyscanner,yytext,yyleng);
1361                                           }
1362                                         }
1363 <SkipCond>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF]  {
1364                                           bool oldSkip = yyextra->skip;
1365                                           endCondSection(yyscanner);
1366                                           if (oldSkip && !yyextra->skip)
1367                                           {
1368                                             if (yyextra->ccomment)
1369                                             {
1370                                               outputArray(yyscanner,"/** ",4);
1371                                             }
1372                                             BEGIN(yyextra->condCtx);
1373                                           }
1374                                         }
1375 <SkipCComment,SkipCPPComment>[\\@]"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1376                                           bool oldSkip = yyextra->skip;
1377                                           endCondSection(yyscanner);
1378                                           if (oldSkip && !yyextra->skip)
1379                                           {
1380                                             BEGIN(yyextra->condCtx);
1381                                           }
1382                                         }
1383 <SkipVerbatim>[\\@]("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}""f}") { /* end of verbatim block */
1384                                           outputArray(yyscanner,yytext,yyleng);
1385                                           if (yytext[1]=='f' && yyextra->blockName=="f")
1386                                           {
1387                                             BEGIN(SkipCComment);
1388                                           }
1389                                           else if (&yytext[4]==yyextra->blockName)
1390                                           {
1391                                             BEGIN(SkipCComment);
1392                                           }
1393                                         }
1394 <SkipVerbatim>^({B}*"*"+)?{B}{0,3}"~~~"[~]*                 {
1395                                           outputArray(yyscanner,yytext,yyleng);
1396                                           if (yyextra->fenceSize==(yy_size_t)yyleng)
1397                                           {
1398                                             BEGIN(SkipCComment);
1399                                           }
1400                                         }
1401 <SkipVerbatim>^({B}*"*"+)?{B}{0,3}"```"[`]*                 {
1402                                           outputArray(yyscanner,yytext,yyleng);
1403                                           if (yyextra->fenceSize==(yy_size_t)yyleng)
1404                                           {
1405                                             BEGIN(SkipCComment);
1406                                           }
1407                                         }
1408 <SkipVerbatim>{CCE}|{CCS}                       {
1409                                           outputArray(yyscanner,yytext,yyleng);
1410                                         }
1411 <JavaDocVerbatimCode>"{"                {
1412                                           if (yyextra->javaBlock==0)
1413                                           {
1414                                             REJECT;
1415                                           }
1416                                           else
1417                                           {
1418                                             yyextra->javaBlock++;
1419                                             outputArray(yyscanner,yytext,(int)yyleng);
1420                                           }
1421                                         }
1422 <JavaDocVerbatimCode>"}"                {
1423                                           if (yyextra->javaBlock==0)
1424                                           {
1425                                             REJECT;
1426                                           }
1427                                           else
1428                                           {
1429                                             yyextra->javaBlock--;
1430                                             if (yyextra->javaBlock==0)
1431                                             {
1432                                               outputArray(yyscanner," @endiliteral ",14);
1433                                               BEGIN(SkipCComment);
1434                                             }
1435                                             else
1436                                             {
1437                                               outputArray(yyscanner,yytext,(int)yyleng);
1438                                             }
1439                                           }
1440                                         }
1441 <JavaDocVerbatimCode>\n                 { /* new line in verbatim block */
1442                                           outputArray(yyscanner,yytext,(int)yyleng);
1443                                         }
1444 <JavaDocVerbatimCode>.                  { /* any other character */
1445                                           outputArray(yyscanner,yytext,(int)yyleng);
1446                                         }
1447 <SkipCComment,SkipVerbatim>[^{*\\@\x06~`\n\/]+ {
1448                                           outputArray(yyscanner,yytext,yyleng);
1449                                         }
1450 <SkipCComment,SkipVerbatim>\n           {
1451                                           yyextra->yyLineNr++;
1452                                           outputChar(yyscanner,'\n');
1453                                         }
1454 <SkipCComment,SkipVerbatim>.            {
1455                                           outputChar(yyscanner,*yytext);
1456                                         }
1457 <CopyCComment>[^*a-z_A-Z\x80-\xFF\n]*[^*a-z_A-Z\x80-\xFF\\\n] {
1458                                           yyextra->defLitText+=yytext;
1459                                           yyextra->defText+=escapeAt(yytext);
1460                                         }
1461 <CopyCComment>\\[\r]?\n                 {
1462                                           yyextra->defLitText+=yytext;
1463                                           yyextra->defText+=" ";
1464                                           yyextra->yyLineNr++;
1465                                           yyextra->yyMLines++;
1466                                         }
1467 <CopyCComment>{CCE}                     {
1468                                           yyextra->defLitText+=yytext;
1469                                           yyextra->defText+=yytext;
1470                                           BEGIN(yyextra->lastCContext);
1471                                         }
1472 <CopyCComment>\n                        {
1473                                           yyextra->yyLineNr++;
1474                                           yyextra->defLitText+=yytext;
1475                                           yyextra->defText+=' ';
1476                                         }
1477 <RemoveCComment>{CCE}{B}*"#"            { // see bug 594021 for a usecase for this rule
1478                                           if (yyextra->lastCContext==SkipCPPBlock)
1479                                           {
1480                                             BEGIN(SkipCommand);
1481                                           }
1482                                           else
1483                                           {
1484                                             REJECT;
1485                                           }
1486                                         }
1487 <RemoveCComment>{CCE}                   { BEGIN(yyextra->lastCContext); }
1488 <RemoveCComment>{CPPC}
1489 <RemoveCComment>{CCS}
1490 <RemoveCComment>[^*\x06\n]+
1491 <RemoveCComment>\n                      { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
1492 <RemoveCComment>.
1493 <SkipCPPComment>[^\n\/\\@]+             {
1494                                           outputArray(yyscanner,yytext,yyleng);
1495                                         }
1496 <SkipCPPComment,RemoveCPPComment>\n     {
1497                                           unput(*yytext);
1498                                           BEGIN(yyextra->lastCPPContext);
1499                                         }
1500 <SkipCPPComment>{CCS}                   {
1501                                           outputChar(yyscanner,'/');outputChar(yyscanner,'*');
1502                                         }
1503 <SkipCPPComment>{CPPC}                  {
1504                                           outputChar(yyscanner,'/');outputChar(yyscanner,'/');
1505                                         }
1506 <SkipCPPComment>[^\x06\@\\\n]+          {
1507                                           outputArray(yyscanner,yytext,yyleng);
1508                                         }
1509 <SkipCPPComment>.                       {
1510                                           outputChar(yyscanner,*yytext);
1511                                         }
1512 <RemoveCPPComment>{CCS}
1513 <RemoveCPPComment>{CPPC}
1514 <RemoveCPPComment>[^\x06\n]+
1515 <RemoveCPPComment>.
1516 <DefineText>"#"/{IDSTART}               {
1517                                           outputChar(yyscanner,' ');
1518                                           yyextra->quoteArg=TRUE;
1519                                           yyextra->idStart=true;
1520                                           yyextra->defLitText+=yytext;
1521                                         }
1522 <DefineText,CopyCComment>{ID}           {
1523                                           yyextra->defLitText+=yytext;
1524                                           if (YY_START == DefineText) outputSpaces(yyscanner,yytext);
1525                                           if (yyextra->quoteArg)
1526                                           {
1527                                             yyextra->defText+="\"";
1528                                           }
1529                                           if (yyextra->defArgs>0)
1530                                           {
1531                                             auto it = yyextra->argMap.find(yytext);
1532                                             if (it!=yyextra->argMap.end())
1533                                             {
1534                                               int n = it->second;
1535                                               yyextra->defText+='@';
1536                                               yyextra->defText+=QCString().setNum(n);
1537                                             }
1538                                             else
1539                                             {
1540                                               if (yyextra->idStart)
1541                                               {
1542                                                 warn(yyextra->fileName,yyextra->yyLineNr,
1543                                                   "'#' is not followed by a macro parameter '%s': '%s'",
1544                                                   qPrint(yyextra->defName),qPrint(yyextra->defLitText.stripWhiteSpace()));
1545                                               }
1546                                               yyextra->defText+=yytext;
1547                                             }
1548                                           }
1549                                           else
1550                                           {
1551                                             yyextra->defText+=yytext;
1552                                           }
1553                                           if (yyextra->quoteArg)
1554                                           {
1555                                             yyextra->defText+="\"";
1556                                           }
1557                                           yyextra->quoteArg=FALSE;
1558                                           yyextra->idStart=false;
1559                                         }
1560 <CopyCComment>.                         {
1561                                           yyextra->defLitText+=yytext;
1562                                           yyextra->defText+=yytext;
1563                                         }
1564 <DefineText>\\[\r]?\n                   {
1565                                           yyextra->defLitText+=yytext;
1566                                           outputChar(yyscanner,'\n');
1567                                           yyextra->defText += ' ';
1568                                           yyextra->yyLineNr++;
1569                                           yyextra->yyMLines++;
1570                                         }
1571 <DefineText>\n                          {
1572                                           QCString comment=extractTrailingComment(yyextra->defLitText);
1573                                           yyextra->defText = yyextra->defText.stripWhiteSpace();
1574                                           if (yyextra->defText.startsWith("##"))
1575                                           {
1576                                             warn(yyextra->fileName,yyextra->yyLineNr,
1577                                                  "'##' cannot occur at the beginning of a macro definition '%s': '%s'",
1578                                                  qPrint(yyextra->defName),qPrint(yyextra->defLitText.stripWhiteSpace()));
1579                                           }
1580                                           else if (yyextra->defText.endsWith("##"))
1581                                           {
1582                                             warn(yyextra->fileName,yyextra->yyLineNr,
1583                                                  "'##' cannot occur at the end of a macro definition '%s': '%s'",
1584                                                  qPrint(yyextra->defName),qPrint(yyextra->defLitText.stripWhiteSpace()));
1585                                           }
1586                                           else if (yyextra->defText.endsWith("#"))
1587                                           {
1588                                             warn(yyextra->fileName,yyextra->yyLineNr,
1589                                                  "expected formal parameter after # in macro definition '%s': '%s'",
1590                                                  qPrint(yyextra->defName),qPrint(yyextra->defLitText.stripWhiteSpace()));
1591                                           }
1592                                           yyextra->defLitText+=yytext;
1593                                           if (!comment.isEmpty())
1594                                           {
1595                                             outputString(yyscanner,comment);
1596                                             yyextra->defLitText=yyextra->defLitText.left(yyextra->defLitText.length()-comment.length()-1);
1597                                           }
1598                                           outputChar(yyscanner,'\n');
1599                                           Define *def=0;
1600                                           //printf("Define name='%s' text='%s' litTexti='%s'\n",qPrint(yyextra->defName),qPrint(yyextra->defText),qPrint(yyextra->defLitText));
1601                                           if (yyextra->includeStack.empty() || yyextra->curlyCount>0)
1602                                           {
1603                                             addMacroDefinition(yyscanner);
1604                                           }
1605                                           def=isDefined(yyscanner,yyextra->defName);
1606                                           if (def==0) // new define
1607                                           {
1608                                             //printf("new define '%s'!\n",qPrint(yyextra->defName));
1609                                             addDefine(yyscanner);
1610                                           }
1611                                           else if (def /*&& macroIsAccessible(def)*/)
1612                                                // name already exists
1613                                           {
1614                                             //printf("existing define!\n");
1615                                             //printf("define found\n");
1616                                             if (def->undef) // undefined name
1617                                             {
1618                                               def->undef = FALSE;
1619                                               def->name = yyextra->defName;
1620                                               def->definition = yyextra->defText.stripWhiteSpace();
1621                                               def->nargs = yyextra->defArgs;
1622                                               def->fileName = yyextra->fileName;
1623                                               def->lineNr = yyextra->yyLineNr-yyextra->yyMLines;
1624                                               def->columnNr = yyextra->yyColNr;
1625                                             }
1626                                             else
1627                                             {
1628                                               //printf("error: define %s is defined more than once!\n",qPrint(yyextra->defName));
1629                                             }
1630                                           }
1631                                           yyextra->argMap.clear();
1632                                           yyextra->yyLineNr++;
1633                                           yyextra->yyColNr=1;
1634                                           yyextra->lastGuardName.resize(0);
1635                                           BEGIN(Start);
1636                                         }
1637 <DefineText>{B}*                        { outputString(yyscanner,yytext);
1638                                           yyextra->defText += ' ';
1639                                           yyextra->defLitText+=yytext;
1640                                         }
1641 <DefineText>{B}*"##"{B}*                { outputString(yyscanner,substitute(yytext,"##","  "));
1642                                           yyextra->defText += "##";
1643                                           yyextra->defLitText+=yytext;
1644                                         }
1645 <DefineText>"@"                         { outputString(yyscanner,substitute(yytext,"@@","  "));
1646                                           yyextra->defText += "@@";
1647                                           yyextra->defLitText+=yytext;
1648                                         }
1649 <DefineText>\"                          {
1650                                           outputChar(yyscanner,' ');
1651                                           yyextra->defText += *yytext;
1652                                           yyextra->defLitText+=yytext;
1653                                           if (!yyextra->insideComment)
1654                                           {
1655                                             BEGIN(SkipDoubleQuote);
1656                                           }
1657                                         }
1658 <DefineText>\'                          {
1659                                           outputChar(yyscanner,' ');
1660                                           yyextra->defText += *yytext;
1661                                           yyextra->defLitText+=yytext;
1662                                           if (!yyextra->insideComment)
1663                                           {
1664                                             BEGIN(SkipSingleQuote);
1665                                           }
1666                                         }
1667 <SkipDoubleQuote>{CPPC}[/]?             { outputSpaces(yyscanner,yytext);
1668                                           yyextra->defText += yytext;
1669                                           yyextra->defLitText+=yytext;
1670                                         }
1671 <SkipDoubleQuote>{CCS}[*]?              { outputSpaces(yyscanner,yytext);
1672                                           yyextra->defText += yytext;
1673                                           yyextra->defLitText+=yytext;
1674                                         }
1675 <SkipDoubleQuote>\"                     {
1676                                           outputChar(yyscanner,' ');
1677                                           yyextra->defText += *yytext;
1678                                           yyextra->defLitText+=yytext;
1679                                           BEGIN(DefineText);
1680                                         }
1681 <SkipSingleQuote,SkipDoubleQuote>\\.    {
1682                                           outputSpaces(yyscanner,yytext);
1683                                           yyextra->defText += yytext;
1684                                           yyextra->defLitText+=yytext;
1685                                         }
1686 <SkipSingleQuote>\'                     {
1687                                           outputChar(yyscanner,' ');
1688                                           yyextra->defText += *yytext;
1689                                           yyextra->defLitText+=yytext;
1690                                           BEGIN(DefineText);
1691                                         }
1692 <SkipDoubleQuote,SkipSingleQuote>.      { outputSpace(yyscanner,yytext[0]);
1693                                           yyextra->defText    += *yytext;
1694                                           yyextra->defLitText += *yytext;
1695                                         }
1696 <DefineText>.                           { outputSpace(yyscanner,yytext[0]);
1697                                           yyextra->defText    += *yytext;
1698                                           yyextra->defLitText += *yytext;
1699                                         }
1700 <<EOF>>                                 {
1701                                           DBG_CTX((stderr,"End of include file\n"));
1702                                           //printf("Include stack depth=%d\n",yyextra->includeStack.size());
1703                                           if (yyextra->includeStack.empty())
1704                                           {
1705                                             DBG_CTX((stderr,"Terminating scanner!\n"));
1706                                             yyterminate();
1707                                           }
1708                                           else
1709                                           {
1710                                             QCString toFileName = yyextra->fileName;
1711                                             const std::unique_ptr<FileState> &fs=yyextra->includeStack.back();
1712                                             //fileDefineCache->merge(yyextra->fileName,fs->fileName);
1713                                             YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
1714                                             yy_switch_to_buffer( fs->bufState, yyscanner );
1715                                             yy_delete_buffer( oldBuf, yyscanner );
1716                                             yyextra->yyLineNr    = fs->lineNr;
1717                                             //preYYin = fs->oldYYin;
1718                                             yyextra->inputBuf    = fs->oldFileBuf;
1719                                             yyextra->inputBufPos = fs->oldFileBufPos;
1720                                             yyextra->curlyCount  = fs->curlyCount;
1721                                             setFileName(yyscanner,fs->fileName);
1722                                             DBG_CTX((stderr,"######## FileName %s\n",qPrint(yyextra->fileName)));
1723 
1724                                             // Deal with file changes due to
1725                                             // #include's within { .. } blocks
1726                                             QCString lineStr(15+yyextra->fileName.length());
1727                                             lineStr.sprintf("# %d \"%s\" 2",yyextra->yyLineNr,qPrint(yyextra->fileName));
1728                                             outputString(yyscanner,lineStr);
1729 
1730                                             yyextra->includeStack.pop_back();
1731 
1732                                             {
1733                                               std::lock_guard<std::mutex> lock(g_globalDefineMutex);
1734                                               // to avoid deadlocks we allow multiple threads to process the same header file.
1735                                               // The first one to finish will store the results globally. After that the
1736                                               // next time the same file is encountered, the stored data is used and the file
1737                                               // is not processed again.
1738                                               if (!g_defineManager.alreadyProcessed(toFileName.str()))
1739                                               {
1740                                                 // now that the file is completely processed, prevent it from processing it again
1741                                                 g_defineManager.addInclude(yyextra->fileName.str(),toFileName.str());
1742                                                 g_defineManager.store(toFileName.str(),yyextra->localDefines);
1743                                               }
1744                                               else
1745                                               {
1746                                                 if (Debug::isFlagSet(Debug::Preprocessor))
1747                                                 {
1748                                                   Debug::print(Debug::Preprocessor,0,"#include %s: was already processed by another thread! not storing data...\n",qPrint(toFileName));
1749                                                 }
1750                                               }
1751                                             }
1752                                             // move the local macros definitions for in this file to the translation unit context
1753                                             for (const auto &kv : yyextra->localDefines)
1754                                             {
1755                                               auto pair = yyextra->contextDefines.insert(kv);
1756                                               if (!pair.second) // define already in context -> replace with local version
1757                                               {
1758                                                 yyextra->contextDefines.erase(pair.first);
1759                                                 yyextra->contextDefines.insert(kv);
1760                                               }
1761                                             }
1762                                             yyextra->localDefines.clear();
1763                                           }
1764                                         }
1765 <*>{CCS}/{CCE}                          |
1766 <*>{CCS}[*!]?                           {
1767                                           if (YY_START==SkipVerbatim || YY_START==SkipCond)
1768                                           {
1769                                             REJECT;
1770                                           }
1771                                           else
1772                                           {
1773                                             outputArray(yyscanner,yytext,yyleng);
1774                                             yyextra->lastCContext=YY_START;
1775                                             yyextra->commentCount=1;
1776                                             if (yyleng==3)
1777                                             {
1778                                               yyextra->isSpecialComment = true;
1779                                               yyextra->lastGuardName.resize(0); // reset guard in case the #define is documented!
1780                                             }
1781                                             else
1782                                             {
1783                                               yyextra->isSpecialComment = false;
1784                                             }
1785                                             BEGIN(SkipCComment);
1786                                           }
1787                                         }
1788 <*>{CPPC}[/!]?                          {
1789                                           if (YY_START==SkipVerbatim || YY_START==SkipCond || getLanguageFromFileName(yyextra->fileName)==SrcLangExt_Fortran)
1790                                           {
1791                                             REJECT;
1792                                           }
1793                                           else
1794                                           {
1795                                             outputArray(yyscanner,yytext,yyleng);
1796                                             yyextra->lastCPPContext=YY_START;
1797                                             if (yyleng==3)
1798                                             {
1799                                               yyextra->isSpecialComment = true;
1800                                               yyextra->lastGuardName.resize(0); // reset guard in case the #define is documented!
1801                                             }
1802                                             else
1803                                             {
1804                                               yyextra->isSpecialComment = false;
1805                                             }
1806                                             BEGIN(SkipCPPComment);
1807                                           }
1808                                         }
1809 <*>\n                                   {
1810                                           outputChar(yyscanner,'\n');
1811                                           yyextra->yyLineNr++;
1812                                         }
1813 <*>.                                    {
1814                                           yyextra->expectGuard = FALSE;
1815                                           outputChar(yyscanner,*yytext);
1816                                         }
1817 
1818 %%
1819 
1820 /////////////////////////////////////////////////////////////////////////////////////
1821 
1822 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
1823 {
1824   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1825   yy_size_t bytesInBuf = state->inputBuf->curPos()-state->inputBufPos;
1826   yy_size_t bytesToCopy = std::min(max_size,bytesInBuf);
1827   memcpy(buf,state->inputBuf->data()+state->inputBufPos,bytesToCopy);
1828   state->inputBufPos+=bytesToCopy;
1829   return bytesToCopy;
1830 }
1831 
1832 static void setFileName(yyscan_t yyscanner,const QCString &name)
1833 {
1834   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1835   bool ambig;
1836   FileInfo fi(name.str());
1837   state->fileName=fi.absFilePath();
1838   state->yyFileDef=findFileDef(Doxygen::inputNameLinkedMap,state->fileName,ambig);
1839   if (state->yyFileDef==0) // if this is not an input file check if it is an
1840                       // include file
1841   {
1842     state->yyFileDef=findFileDef(Doxygen::includeNameLinkedMap,state->fileName,ambig);
1843   }
1844   //printf("setFileName(%s) state->fileName=%s state->yyFileDef=%p\n",
1845   //    name,qPrint(state->fileName),state->yyFileDef);
1846   if (state->yyFileDef && state->yyFileDef->isReference()) state->yyFileDef=0;
1847   state->insideCS = getLanguageFromFileName(state->fileName)==SrcLangExt_CSharp;
1848   state->insideFtn = getLanguageFromFileName(state->fileName)==SrcLangExt_Fortran;
1849   state->isSource = guessSection(state->fileName);
1850 }
1851 
1852 static void incrLevel(yyscan_t yyscanner)
1853 {
1854   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1855   state->levelGuard.push(false);
1856   //printf("%s line %d: incrLevel %d\n",qPrint(yyextra->fileName),yyextra->yyLineNr,yyextra->levelGuard.size());
1857 }
1858 
1859 static void decrLevel(yyscan_t yyscanner)
1860 {
1861   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1862   //printf("%s line %d: decrLevel %d\n",qPrint(state->fileName),state->yyLineNr,state->levelGuard.size());
1863   if (!state->levelGuard.empty())
1864   {
1865     state->levelGuard.pop();
1866   }
1867   else
1868   {
1869     warn(state->fileName,state->yyLineNr,"More #endif's than #if's found.\n");
1870   }
1871 }
1872 
1873 static bool otherCaseDone(yyscan_t yyscanner)
1874 {
1875   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1876   if (state->levelGuard.empty())
1877   {
1878     warn(state->fileName,state->yyLineNr,"Found an #else without a preceding #if.\n");
1879     return TRUE;
1880   }
1881   else
1882   {
1883     return state->levelGuard.top();
1884   }
1885 }
1886 
1887 static void setCaseDone(yyscan_t yyscanner,bool value)
1888 {
1889   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1890   state->levelGuard.top()=value;
1891 }
1892 
1893 
1894 static FileState *checkAndOpenFile(yyscan_t yyscanner,const QCString &fileName,bool &alreadyProcessed)
1895 {
1896   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1897   alreadyProcessed = FALSE;
1898   FileState *fs = 0;
1899   //printf("checkAndOpenFile(%s)\n",qPrint(fileName));
1900   FileInfo fi(fileName.str());
1901   if (fi.exists() && fi.isFile())
1902   {
1903     const StringVector &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
1904     if (patternMatch(fi,exclPatterns)) return 0;
1905 
1906     QCString absName = fi.absFilePath();
1907 
1908     // global guard
1909     if (state->curlyCount==0) // not #include inside { ... }
1910     {
1911       std::lock_guard<std::mutex> lock(g_globalDefineMutex);
1912       if (g_defineManager.alreadyProcessed(absName.str()))
1913       {
1914         alreadyProcessed = TRUE;
1915         //printf("  already included 1\n");
1916         return 0; // already done
1917       }
1918     }
1919     // check include stack for absName
1920 
1921     alreadyProcessed = std::any_of(
1922       state->includeStack.begin(),
1923       state->includeStack.end(),
1924       [absName](const std::unique_ptr<FileState> &lfs)
1925         { return lfs->fileName==absName; }
1926     );
1927 
1928     if (alreadyProcessed)
1929     {
1930       //printf("  already included 2\n");
1931       return 0;
1932     }
1933     //printf("#include %s\n",qPrint(absName));
1934 
1935     fs = new FileState(static_cast<uint>(fi.size())+4096);
1936     if (!readInputFile(absName,fs->fileBuf))
1937     { // error
1938       //printf("  error reading\n");
1939       delete fs;
1940       fs=0;
1941     }
1942     else
1943     {
1944       fs->oldFileBuf    = state->inputBuf;
1945       fs->oldFileBufPos = state->inputBufPos;
1946     }
1947   }
1948   return fs;
1949 }
1950 
1951 static FileState *findFile(yyscan_t yyscanner, const QCString &fileName,bool localInclude,bool &alreadyProcessed)
1952 {
1953   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
1954   //printf("** findFile(%s,%d) state->fileName=%s\n",qPrint(fileName),localInclude,qPrint(state->fileName));
1955   if (Portable::isAbsolutePath(fileName))
1956   {
1957     FileState *fs = checkAndOpenFile(yyscanner,fileName,alreadyProcessed);
1958     if (fs)
1959     {
1960       setFileName(yyscanner,fileName);
1961       state->yyLineNr=1;
1962       return fs;
1963     }
1964     else if (alreadyProcessed)
1965     {
1966       return 0;
1967     }
1968   }
1969   if (localInclude && !state->fileName.isEmpty())
1970   {
1971     FileInfo fi(state->fileName.str());
1972     if (fi.exists())
1973     {
1974       QCString absName = QCString(fi.dirPath(TRUE))+"/"+fileName;
1975       FileState *fs = checkAndOpenFile(yyscanner,absName,alreadyProcessed);
1976       if (fs)
1977       {
1978         setFileName(yyscanner,absName);
1979         state->yyLineNr=1;
1980         return fs;
1981       }
1982       else if (alreadyProcessed)
1983       {
1984         return 0;
1985       }
1986     }
1987   }
1988   if (state->pathList.empty())
1989   {
1990     return 0;
1991   }
1992   for (auto path : state->pathList)
1993   {
1994     std::string absName = (path+"/"+fileName).str();
1995     //printf("  Looking for %s in %s\n",fileName,path.c_str());
1996     FileState *fs = checkAndOpenFile(yyscanner,absName.c_str(),alreadyProcessed);
1997     if (fs)
1998     {
1999       setFileName(yyscanner,absName.c_str());
2000       state->yyLineNr=1;
2001       //printf("  -> found it\n");
2002       return fs;
2003     }
2004     else if (alreadyProcessed)
2005     {
2006       return 0;
2007     }
2008   }
2009   return 0;
2010 }
2011 
2012 static QCString extractTrailingComment(const QCString &s)
2013 {
2014   if (s.isEmpty()) return "";
2015   int i=(int)s.length()-1;
2016   while (i>=0)
2017   {
2018     char c=s[i];
2019     switch (c)
2020     {
2021       case '/':
2022         {
2023           i--;
2024           if (i>=0 && s[i]=='*') // end of a comment block
2025           {
2026             i--;
2027             while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--;
2028             if (i==0)
2029             {
2030               i++;
2031             }
2032             // only /*!< or /**< are treated as a comment for the macro name,
2033             // otherwise the comment is treated as part of the macro definition
2034             return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : "";
2035           }
2036           else
2037           {
2038             return "";
2039           }
2040         }
2041         break;
2042         // whitespace or line-continuation
2043       case ' ':
2044       case '\t':
2045       case '\r':
2046       case '\n':
2047       case '\\':
2048         break;
2049       default:
2050         return "";
2051     }
2052     i--;
2053   }
2054   return "";
2055 }
2056 
2057 static int getNextChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos);
2058 static int getCurrentChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint pos);
2059 static void unputChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos,char c);
2060 static bool expandExpression(yyscan_t yyscanner,QCString &expr,QCString *rest,int pos,int level);
2061 
2062 static QCString stringize(const QCString &s)
2063 {
2064   QCString result;
2065   uint i=0;
2066   bool inString=FALSE;
2067   bool inChar=FALSE;
2068   char c,pc;
2069   while (i<s.length())
2070   {
2071     if (!inString && !inChar)
2072     {
2073       while (i<s.length() && !inString && !inChar)
2074       {
2075         c=s.at(i++);
2076         if (c=='"')
2077         {
2078           result+="\\\"";
2079           inString=TRUE;
2080         }
2081         else if (c=='\'')
2082         {
2083           result+=c;
2084           inChar=TRUE;
2085         }
2086         else
2087         {
2088           result+=c;
2089         }
2090       }
2091     }
2092     else if (inChar)
2093     {
2094       while (i<s.length() && inChar)
2095       {
2096         c=s.at(i++);
2097         if (c=='\'')
2098         {
2099           result+='\'';
2100           inChar=FALSE;
2101         }
2102         else if (c=='\\')
2103         {
2104           result+="\\\\";
2105         }
2106         else
2107         {
2108           result+=c;
2109         }
2110       }
2111     }
2112     else
2113     {
2114       pc=0;
2115       while (i<s.length() && inString)
2116       {
2117         c=s.at(i++);
2118         if (c=='"')
2119         {
2120           result+="\\\"";
2121           inString= pc=='\\';
2122         }
2123         else if (c=='\\')
2124           result+="\\\\";
2125         else
2126           result+=c;
2127         pc=c;
2128       }
2129     }
2130   }
2131   //printf("stringize '%s'->'%s'\n",qPrint(s),qPrint(result));
2132   return result;
2133 }
2134 
2135 /*! Execute all ## operators in expr.
2136  * If the macro name before or after the operator contains a no-rescan
2137  * marker (@-) then this is removed (before the concatenated macro name
2138  * may be expanded again.
2139  */
2140 static void processConcatOperators(QCString &expr)
2141 {
2142   if (expr.isEmpty()) return;
2143   //printf("processConcatOperators: in='%s'\n",qPrint(expr));
2144   std::string e = expr.str();
2145   static const reg::Ex r(R"(\s*##\s*)");
2146   reg::Iterator end;
2147 
2148   size_t i=0;
2149   for (;;)
2150   {
2151     reg::Iterator it(e,r,i);
2152     if (it!=end)
2153     {
2154       const auto &match = *it;
2155       size_t n = match.position();
2156       size_t l = match.length();
2157       //printf("Match: '%s'\n",qPrint(expr.mid(i)));
2158       if (n+l+1<e.length() && e[static_cast<int>(n+l)]=='@' && expr[static_cast<int>(n+l+1)]=='-')
2159       {
2160         // remove no-rescan marker after ID
2161         l+=2;
2162       }
2163       //printf("found '%s'\n",qPrint(expr.mid(n,l)));
2164       // remove the ## operator and the surrounding whitespace
2165       e=e.substr(0,n)+e.substr(n+l);
2166       int k=static_cast<int>(n)-1;
2167       while (k>=0 && isId(e[k])) k--;
2168       if (k>0 && e[k]=='-' && e[k-1]=='@')
2169       {
2170         // remove no-rescan marker before ID
2171         e=e.substr(0,k-1)+e.substr(k+1);
2172         n-=2;
2173       }
2174       i=n;
2175     }
2176     else
2177     {
2178       break;
2179     }
2180   }
2181 
2182   expr = e;
2183 
2184   //printf("processConcatOperators: out='%s'\n",qPrint(expr));
2185 }
2186 
2187 static void returnCharToStream(yyscan_t yyscanner,char c)
2188 {
2189   struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
2190   unput(c);
2191 }
2192 
2193 static inline void addTillEndOfString(yyscan_t yyscanner,const QCString &expr,QCString *rest,
2194                                        uint &pos,char term,QCString &arg)
2195 {
2196   int cc;
2197   while ((cc=getNextChar(yyscanner,expr,rest,pos))!=EOF && cc!=0)
2198   {
2199     if (cc=='\\') arg+=(char)cc,cc=getNextChar(yyscanner,expr,rest,pos);
2200     else if (cc==term) return;
2201     arg+=(char)cc;
2202   }
2203 }
2204 
2205 /*! replaces the function macro \a def whose argument list starts at
2206  * \a pos in expression \a expr.
2207  * Notice that this routine may scan beyond the \a expr string if needed.
2208  * In that case the characters will be read from the input file.
2209  * The replacement string will be returned in \a result and the
2210  * length of the (unexpanded) argument list is stored in \a len.
2211  */
2212 static bool replaceFunctionMacro(yyscan_t yyscanner,const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result,int level)
2213 {
2214   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2215   //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());
2216   uint j=pos;
2217   len=0;
2218   result.resize(0);
2219   int cc;
2220   while ((cc=getCurrentChar(yyscanner,expr,rest,j))!=EOF && isspace(cc))
2221   {
2222     len++;
2223     getNextChar(yyscanner,expr,rest,j);
2224   }
2225   if (cc!='(')
2226   {
2227     unputChar(yyscanner,expr,rest,j,' ');
2228     return FALSE;
2229   }
2230   getNextChar(yyscanner,expr,rest,j); // eat the '(' character
2231 
2232   std::map<std::string,std::string> argTable;  // list of arguments
2233   QCString arg;
2234   int argCount=0;
2235   bool done=FALSE;
2236 
2237   // PHASE 1: read the macro arguments
2238   if (def->nargs==0)
2239   {
2240     while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2241     {
2242       char c = (char)cc;
2243       if (c==')') break;
2244     }
2245   }
2246   else
2247   {
2248     while (!done && (argCount<def->nargs || def->varArgs) &&
2249         ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2250           )
2251     {
2252       char c=(char)cc;
2253       if (c=='(') // argument is a function => search for matching )
2254       {
2255         int lvl=1;
2256         arg+=c;
2257         //char term='\0';
2258         while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2259         {
2260           c=(char)cc;
2261           //printf("processing %c: term=%c (%d)\n",c,term,term);
2262           if (c=='\'' || c=='\"') // skip ('s and )'s inside strings
2263           {
2264             arg+=c;
2265             addTillEndOfString(yyscanner,expr,rest,j,c,arg);
2266           }
2267           if (c==')')
2268           {
2269             lvl--;
2270             arg+=c;
2271             if (lvl==0) break;
2272           }
2273           else if (c=='(')
2274           {
2275             lvl++;
2276             arg+=c;
2277           }
2278           else
2279             arg+=c;
2280         }
2281       }
2282       else if (c==')' || c==',') // last or next argument found
2283       {
2284         if (c==',' && argCount==def->nargs-1 && def->varArgs)
2285         {
2286           arg=arg.stripWhiteSpace();
2287           arg+=',';
2288         }
2289         else
2290         {
2291           QCString argKey;
2292           argKey.sprintf("@%d",argCount++); // key name
2293           arg=arg.stripWhiteSpace();
2294           // add argument to the lookup table
2295           argTable.emplace(toStdString(argKey), toStdString(arg));
2296           arg.resize(0);
2297           if (c==')') // end of the argument list
2298           {
2299             done=TRUE;
2300           }
2301         }
2302       }
2303       else if (c=='\"') // append literal strings
2304       {
2305         arg+=c;
2306         bool found=FALSE;
2307         while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2308         {
2309           found = cc=='"';
2310           if (cc=='\\')
2311           {
2312             c=(char)cc;
2313             arg+=c;
2314             if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break;
2315           }
2316           c=(char)cc;
2317           arg+=c;
2318         }
2319       }
2320       else if (c=='\'') // append literal characters
2321       {
2322         arg+=c;
2323         bool found=FALSE;
2324         while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2325         {
2326           found = cc=='\'';
2327           if (cc=='\\')
2328           {
2329             c=(char)cc;
2330             arg+=c;
2331             if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break;
2332           }
2333           c=(char)cc;
2334           arg+=c;
2335         }
2336       }
2337       else if (c=='/') // possible start of a comment
2338       {
2339         char prevChar = '\0';
2340         arg+=c;
2341         if ((cc=getCurrentChar(yyscanner,expr,rest,j)) == '*') // we have a comment
2342         {
2343           while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2344           {
2345             c=(char)cc;
2346             arg+=c;
2347             if (c == '/' && prevChar == '*') break; // we have an end of comment
2348             prevChar = c;
2349           }
2350         }
2351       }
2352       else // append other characters
2353       {
2354         arg+=c;
2355       }
2356     }
2357   }
2358 
2359   // PHASE 2: apply the macro function
2360   if (argCount==def->nargs || // same number of arguments
2361       (argCount>=def->nargs-1 && def->varArgs)) // variadic macro with at least as many
2362                                                 // params as the non-variadic part (see bug731985)
2363   {
2364     uint k=0;
2365     // substitution of all formal arguments
2366     QCString resExpr;
2367     const QCString d=def->definition.stripWhiteSpace();
2368     //printf("Macro definition: '%s'\n",qPrint(d));
2369     bool inString=FALSE;
2370     while (k<d.length())
2371     {
2372       if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
2373       {
2374         if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
2375         {
2376           k+=2;
2377           resExpr+="@@"; // we unescape these later
2378         }
2379         else if (d.at(k+1)=='-') // no-rescan marker
2380         {
2381           k+=2;
2382           resExpr+="@-";
2383         }
2384         else // argument marker => read the argument number
2385         {
2386           QCString key="@";
2387           bool hash=FALSE;
2388           int l=k-1;
2389           // search for ## backward
2390           if (l>=0 && d.at(l)=='"') l--;
2391           while (l>=0 && d.at(l)==' ') l--;
2392           if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
2393           k++;
2394           // scan the number
2395           while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
2396           if (!hash)
2397           {
2398             // search for ## forward
2399             l=k;
2400             if (l<(int)d.length() && d.at(l)=='"') l++;
2401             while (l<(int)d.length() && d.at(l)==' ') l++;
2402             if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
2403           }
2404           //printf("request key %s result %s\n",qPrint(key),argTable[key]->data());
2405           auto it = argTable.find(key.str());
2406           if (it!=argTable.end())
2407           {
2408             QCString substArg = it->second.c_str();
2409             //printf("substArg='%s'\n",qPrint(substArg));
2410             // only if no ## operator is before or after the argument
2411             // marker we do macro expansion.
2412             if (!hash)
2413             {
2414               expandExpression(yyscanner,substArg,0,0,level+1);
2415             }
2416             if (inString)
2417             {
2418               //printf("'%s'=stringize('%s')\n",qPrint(stringize(*subst)),subst->data());
2419 
2420               // if the marker is inside a string (because a # was put
2421               // before the macro name) we must escape " and \ characters
2422               resExpr+=stringize(substArg);
2423             }
2424             else
2425             {
2426               if (hash && substArg.isEmpty())
2427               {
2428                 resExpr+="@E"; // empty argument will be remove later on
2429               }
2430               else if (state->nospaces)
2431               {
2432                 resExpr+=substArg;
2433               }
2434               else
2435               {
2436                 resExpr+=" "+substArg+" ";
2437               }
2438             }
2439           }
2440         }
2441       }
2442       else // no marker, just copy
2443       {
2444         if (!inString && d.at(k)=='\"')
2445         {
2446           inString=TRUE; // entering a literal string
2447         }
2448         else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
2449         {
2450           inString=FALSE; // leaving a literal string
2451         }
2452         resExpr+=d.at(k++);
2453       }
2454     }
2455     len=j-pos;
2456     result=resExpr;
2457     //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());
2458     return TRUE;
2459   }
2460   //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());
2461   return FALSE;
2462 }
2463 
2464 
2465 /*! returns the next identifier in string \a expr by starting at position \a p.
2466  * The position of the identifier is returned (or -1 if nothing is found)
2467  * and \a l is its length. Any quoted strings are skipping during the search.
2468  */
2469 static int getNextId(const QCString &expr,int p,int *l)
2470 {
2471   int n;
2472   while (p<(int)expr.length())
2473   {
2474     char c=expr.at(p++);
2475     if (isdigit(c)) // skip number
2476     {
2477       while (p<(int)expr.length() && isId(expr.at(p))) p++;
2478     }
2479     else if (isalpha(c) || c=='_') // read id
2480     {
2481       n=p-1;
2482       while (p<(int)expr.length() && isId(expr.at(p))) p++;
2483       *l=p-n;
2484       return n;
2485     }
2486     else if (c=='"') // skip string
2487     {
2488       char ppc=0,pc=c;
2489       if (p<(int)expr.length()) c=expr.at(p);
2490       while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\')))
2491         // continue as long as no " is found, but ignoring \", but not \\"
2492       {
2493         ppc=pc;
2494         pc=c;
2495         c=expr.at(p);
2496         p++;
2497       }
2498       if (p<(int)expr.length()) ++p; // skip closing quote
2499     }
2500     else if (c=='/') // skip C Comment
2501     {
2502       //printf("Found C comment at p=%d\n",p);
2503       char pc=c;
2504       if (p<(int)expr.length())
2505       {
2506         c=expr.at(p);
2507         if (c=='*')  // Start of C comment
2508         {
2509           p++;
2510           while (p<(int)expr.length() && !(pc=='*' && c=='/'))
2511           {
2512             pc=c;
2513             c=expr.at(p++);
2514           }
2515         }
2516       }
2517       //printf("Found end of C comment at p=%d\n",p);
2518     }
2519   }
2520   return -1;
2521 }
2522 
2523 #define MAX_EXPANSION_DEPTH 50
2524 
2525 /*! performs recursive macro expansion on the string \a expr
2526  *  starting at position \a pos.
2527  *  May read additional characters from the input while re-scanning!
2528  */
2529 static bool expandExpression(yyscan_t yyscanner,QCString &expr,QCString *rest,int pos,int level)
2530 {
2531   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2532   //printf(">expandExpression(expr='%s',rest='%s',pos=%d,level=%d)\n",qPrint(expr),rest ? qPrint(*rest) : "", pos, level);
2533   if (expr.isEmpty())
2534   {
2535     //printf("<expandExpression: empty\n");
2536     return TRUE;
2537   }
2538   if (state->expanded.find(expr.str())!=state->expanded.end() &&
2539       level>MAX_EXPANSION_DEPTH) // check for too deep recursive expansions
2540   {
2541     //printf("<expandExpression: already expanded expr='%s'\n",qPrint(expr));
2542     return FALSE;
2543   }
2544   else
2545   {
2546     state->expanded.insert(expr.str());
2547   }
2548   QCString macroName;
2549   QCString expMacro;
2550   bool definedTest=FALSE;
2551   int i=pos,l,p,len;
2552   int startPos = pos;
2553   int samePosCount=0;
2554   while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
2555   {
2556     bool replaced=FALSE;
2557     macroName=expr.mid(p,l);
2558     //printf(" p=%d macroName=%s\n",p,qPrint(macroName));
2559     if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
2560     {
2561       if (state->expandedDict.find(macroName.str())==state->expandedDict.end()) // expand macro
2562       {
2563         Define *def=isDefined(yyscanner,macroName);
2564         if (macroName=="defined")
2565         {
2566           //printf("found defined inside macro definition '%s'\n",qPrint(expr.right(expr.length()-p)));
2567           definedTest=TRUE;
2568         }
2569         else if (definedTest) // macro name was found after defined
2570         {
2571           if (def) expMacro = " 1 "; else expMacro = " 0 ";
2572           replaced=TRUE;
2573           len=l;
2574           definedTest=FALSE;
2575         }
2576         else if (def && def->nargs==-1) // simple macro
2577         {
2578           // substitute the definition of the macro
2579           //printf("macro '%s'->'%s'\n",qPrint(macroName),qPrint(def->definition));
2580           if (state->nospaces)
2581           {
2582             expMacro=def->definition.stripWhiteSpace();
2583           }
2584           else
2585           {
2586             expMacro=" "+def->definition.stripWhiteSpace()+" ";
2587           }
2588           //expMacro=def->definition.stripWhiteSpace();
2589           replaced=TRUE;
2590           len=l;
2591           //printf("simple macro expansion='%s'->'%s'\n",qPrint(macroName),qPrint(expMacro));
2592         }
2593         else if (def && def->nargs>=0) // function macro
2594         {
2595           //printf(" >>>> call replaceFunctionMacro expr='%s'\n",qPrint(expr));
2596           replaced=replaceFunctionMacro(yyscanner,expr,rest,p+l,len,def,expMacro,level);
2597           //printf(" <<<< call replaceFunctionMacro: replaced=%d\n",replaced);
2598           len+=l;
2599         }
2600         //printf(" macroName='%s' expMacro='%s' replaced=%d\n",qPrint(macroName),qPrint(expMacro),replaced);
2601 
2602         if (replaced) // expand the macro and rescan the expression
2603         {
2604           //printf(" replacing '%s'->'%s'\n",expr.mid(p,qPrint(len)),qPrint(expMacro));
2605           QCString resultExpr=expMacro;
2606           QCString restExpr=expr.right(expr.length()-len-p);
2607           processConcatOperators(resultExpr);
2608           //printf(" macroName=%s restExpr='%s' def->nonRecursive=%d\n",qPrint(macroName),qPrint(restExpr),def->nonRecursive);
2609           bool expanded=false;
2610           if (def && !def->nonRecursive)
2611           {
2612             state->expandedDict.emplace(toStdString(macroName),def);
2613             expanded = expandExpression(yyscanner,resultExpr,&restExpr,0,level+1);
2614             state->expandedDict.erase(toStdString(macroName));
2615           }
2616     else if (def && def->nonRecursive)
2617     {
2618       expanded = true;
2619     }
2620           if (expanded)
2621           {
2622             expr=expr.left(p)+resultExpr+restExpr;
2623             //printf(" new expression: '%s' old i=%d new i=%d\n",qPrint(expr),i,p);
2624             i=p;
2625           }
2626           else
2627           {
2628             expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
2629             i=p+l+2;
2630           }
2631         }
2632         else // move to the next macro name
2633         {
2634           //printf(" moving to the next macro old i=%d new i=%d\n",i,p+l);
2635           i=p+l;
2636         }
2637       }
2638       else // move to the next macro name
2639       {
2640         expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
2641         //printf("macro already expanded, moving to the next macro expr=%s\n",qPrint(expr));
2642         i=p+l+2;
2643         //i=p+l;
2644       }
2645       // check for too many inplace expansions without making progress
2646       if (i==startPos)
2647       {
2648         samePosCount++;
2649       }
2650       else
2651       {
2652         startPos=i;
2653         samePosCount=0;
2654       }
2655       if (samePosCount>MAX_EXPANSION_DEPTH)
2656       {
2657         break;
2658       }
2659     }
2660     else // no re-scan marker found, skip the macro name
2661     {
2662       //printf("skipping marked macro\n");
2663       i=p+l;
2664     }
2665   }
2666   //printf("<expandExpression(expr='%s',rest='%s',pos=%d,level=%d)\n",qPrint(expr),rest ? qPrint(*rest) : "", pos,level);
2667   return TRUE;
2668 }
2669 
2670 /*! @brief Process string or character literal.
2671  *
2672  * \a inputStr should point to the start of a string or character literal.
2673  * the routine will return a pointer to just after the end of the literal
2674  * the character making up the literal will be added to \a result.
2675  */
2676 static const char *processUntilMatchingTerminator(const char *inputStr,QCString &result)
2677 {
2678   if (inputStr==0) return inputStr;
2679   char term = *inputStr; // capture start character of the literal
2680   if (term!='\'' && term!='"') return inputStr; // not a valid literal
2681   char c=term;
2682   // output start character
2683   result+=c;
2684   inputStr++;
2685   while ((c=*inputStr)) // while inside the literal
2686   {
2687     if (c==term) // found end marker of the literal
2688     {
2689       // output end character and stop
2690       result+=c;
2691       inputStr++;
2692       break;
2693     }
2694     else if (c=='\\') // escaped character, process next character
2695                       // as well without checking for end marker.
2696     {
2697       result+=c;
2698       inputStr++;
2699       c=*inputStr;
2700       if (c==0) break; // unexpected end of string after escape character
2701     }
2702     result+=c;
2703     inputStr++;
2704   }
2705   return inputStr;
2706 }
2707 
2708 /*! replaces all occurrences of @@@@ in \a s by @@
2709  *  and removes all occurrences of @@E.
2710  *  All identifiers found are replaced by 0L
2711  */
2712 static QCString removeIdsAndMarkers(const QCString &s)
2713 {
2714   //printf("removeIdsAndMarkers(%s)\n",s);
2715   if (s.isEmpty()) return s;
2716   const char *p=s.data();
2717   char c;
2718   bool inNum=FALSE;
2719   QCString result;
2720   if (p)
2721   {
2722     while ((c=*p))
2723     {
2724       if (c=='@') // replace @@ with @ and remove @E
2725       {
2726         if (*(p+1)=='@')
2727         {
2728           result+=c;
2729         }
2730         else if (*(p+1)=='E')
2731         {
2732           // skip
2733         }
2734         p+=2;
2735       }
2736       else if (isdigit(c)) // number
2737       {
2738         result+=c;
2739         p++;
2740         inNum=TRUE;
2741       }
2742       else if (c=='\'') // quoted character
2743       {
2744         p = processUntilMatchingTerminator(p,result);
2745       }
2746       else if (c=='d' && !inNum) // identifier starting with a 'd'
2747       {
2748         if (qstrncmp(p,"defined ",8)==0 || qstrncmp(p,"defined(",8)==0)
2749                    // defined keyword
2750         {
2751           p+=7; // skip defined
2752         }
2753         else
2754         {
2755           result+="0L";
2756           p++;
2757           while ((c=*p) && isId(c)) p++;
2758         }
2759       }
2760       else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
2761       {
2762         result+="0L";
2763         p++;
2764         while ((c=*p) && isId(c)) p++;
2765         while ((c=*p) && isspace((uchar)c)) p++;
2766         if (*p=='(') // undefined function macro
2767         {
2768           p++;
2769           int count=1;
2770           while ((c=*p++))
2771           {
2772             if (c=='(') count++;
2773             else if (c==')')
2774             {
2775               count--;
2776               if (count==0) break;
2777             }
2778             else if (c=='/')
2779             {
2780               char pc=c;
2781               c=*++p;
2782               if (c=='*') // start of C comment
2783               {
2784                 while (*p && !(pc=='*' && c=='/')) // search end of comment
2785                 {
2786                   pc=c;
2787                   c=*++p;
2788                 }
2789                 p++;
2790               }
2791             }
2792           }
2793         }
2794       }
2795       else if (c=='/') // skip C comments
2796       {
2797         char pc=c;
2798         c=*++p;
2799         if (c=='*') // start of C comment
2800         {
2801           while (*p && !(pc=='*' && c=='/')) // search end of comment
2802           {
2803             pc=c;
2804             c=*++p;
2805           }
2806           p++;
2807         }
2808         else // oops, not comment but division
2809         {
2810           result+=pc;
2811           goto nextChar;
2812         }
2813       }
2814       else
2815       {
2816 nextChar:
2817         result+=c;
2818         char lc=(char)tolower(c);
2819         if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE;
2820         p++;
2821       }
2822     }
2823   }
2824   //printf("removeIdsAndMarkers(%s)=%s\n",s,qPrint(result));
2825   return result;
2826 }
2827 
2828 /*! replaces all occurrences of @@ in \a s by @
2829  *  \par assumption:
2830  *   \a s only contains pairs of @@'s
2831  */
2832 static QCString removeMarkers(const QCString &s)
2833 {
2834   if (s.isEmpty()) return s;
2835   const char *p=s.data();
2836   char c;
2837   QCString result;
2838   if (p)
2839   {
2840     while ((c=*p))
2841     {
2842       switch(c)
2843       {
2844         case '@': // replace @@ with @
2845           {
2846             if (*(p+1)=='@')
2847             {
2848               result+=c;
2849             }
2850             p+=2;
2851           }
2852           break;
2853         case '/': // skip C comments
2854           {
2855             result+=c;
2856             char pc=c;
2857             c=*++p;
2858             if (c=='*') // start of C comment
2859             {
2860               while (*p && !(pc=='*' && c=='/')) // search end of comment
2861               {
2862                 if (*p=='@' && *(p+1)=='@')
2863                   result+=c,p++;
2864                 else
2865                   result+=c;
2866                 pc=c;
2867                 c=*++p;
2868               }
2869               if (*p) result+=c,p++;
2870             }
2871           }
2872           break;
2873         case '"': // skip string literals
2874         case '\'': // skip char literals
2875           p = processUntilMatchingTerminator(p,result);
2876           break;
2877         default:
2878           {
2879             result+=c;
2880             p++;
2881           }
2882           break;
2883       }
2884     }
2885   }
2886   //printf("RemoveMarkers(%s)=%s\n",s,qPrint(result));
2887   return result;
2888 }
2889 
2890 /*! compute the value of the expression in string \a expr.
2891  *  If needed the function may read additional characters from the input.
2892  */
2893 
2894 static bool computeExpression(yyscan_t yyscanner,const QCString &expr)
2895 {
2896   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2897   QCString e=expr;
2898   state->expanded.clear();
2899   expandExpression(yyscanner,e,0,0,0);
2900   //printf("after expansion '%s'\n",qPrint(e));
2901   e = removeIdsAndMarkers(e);
2902   if (e.isEmpty()) return FALSE;
2903   //printf("parsing '%s'\n",qPrint(e));
2904   return state->constExpParser.parse(state->fileName.data(),state->yyLineNr,e.str());
2905 }
2906 
2907 /*! expands the macro definition in \a name
2908  *  If needed the function may read additional characters from the input
2909  */
2910 
2911 static QCString expandMacro(yyscan_t yyscanner,const QCString &name)
2912 {
2913   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2914   QCString n=name;
2915   state->expanded.clear();
2916   expandExpression(yyscanner,n,0,0,0);
2917   n=removeMarkers(n);
2918   //printf("expandMacro '%s'->'%s'\n",qPrint(name),qPrint(n));
2919   return n;
2920 }
2921 
2922 static void addDefine(yyscan_t yyscanner)
2923 {
2924   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2925   Define def;
2926   def.name       = state->defName;
2927   def.definition = state->defText.stripWhiteSpace();
2928   def.nargs      = state->defArgs;
2929   def.fileName   = state->fileName;
2930   def.fileDef    = state->yyFileDef;
2931   def.lineNr     = state->yyLineNr-state->yyMLines;
2932   def.columnNr   = state->yyColNr;
2933   def.varArgs    = state->defVarArgs;
2934   //printf("newDefine: %s %s file: %s\n",qPrint(def.name),qPrint(def.definition),
2935   //    def.fileDef ? qPrint(def.fileDef->name()) : qPrint(def.fileName));
2936   //printf("newDefine: '%s'->'%s'\n",qPrint(def.name),qPrint(def.definition));
2937   if (!def.name.isEmpty() &&
2938       Doxygen::expandAsDefinedSet.find(def.name.str())!=Doxygen::expandAsDefinedSet.end())
2939   {
2940     def.isPredefined=TRUE;
2941   }
2942   auto it = state->localDefines.find(def.name.str());
2943   if (it!=state->localDefines.end()) // redefine
2944   {
2945     state->localDefines.erase(it);
2946   }
2947   state->localDefines.insert(std::make_pair(def.name.str(),def));
2948 }
2949 
2950 static void addMacroDefinition(yyscan_t yyscanner)
2951 {
2952   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2953   if (state->skip) return; // do not add this define as it is inside a
2954                       // conditional section (cond command) that is disabled.
2955 
2956   Define define;
2957   define.fileName = state->fileName;
2958   define.lineNr   = state->yyLineNr - state->yyMLines;
2959   define.columnNr = state->yyColNr;
2960   define.name     = state->defName;
2961   define.args     = state->defArgsStr;
2962   define.fileDef  = state->inputFileDef;
2963 
2964   QCString litText = state->defLitText;
2965   int l=litText.find('\n');
2966   if (l>0 && litText.left(l).stripWhiteSpace()=="\\")
2967   {
2968     // strip first line if it only contains a slash
2969     litText = litText.right(litText.length()-l-1);
2970   }
2971   else if (l>0)
2972   {
2973     // align the items on the first line with the items on the second line
2974     int k=l+1;
2975     const char *p=litText.data()+k;
2976     char c;
2977     while ((c=*p++) && (c==' ' || c=='\t')) k++;
2978     litText=litText.mid(l+1,k-l-1)+litText.stripWhiteSpace();
2979   }
2980   QCString litTextStripped = state->defLitText.stripWhiteSpace();
2981   if (litTextStripped.contains('\n')>=1)
2982   {
2983     define.definition = litText;
2984   }
2985   else
2986   {
2987     define.definition = litTextStripped;
2988   }
2989   {
2990     state->macroDefinitions.push_back(define);
2991   }
2992 }
2993 
2994 static inline void outputChar(yyscan_t yyscanner,char c)
2995 {
2996   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2997   if (state->includeStack.empty() || state->curlyCount>0) state->outputBuf->addChar(c);
2998 }
2999 
3000 static inline void outputArray(yyscan_t yyscanner,const char *a,yy_size_t len)
3001 {
3002   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3003   if (state->includeStack.empty() || state->curlyCount>0) state->outputBuf->addArray(a,static_cast<uint>(len));
3004 }
3005 
3006 static inline void outputString(yyscan_t yyscanner,const QCString &a)
3007 {
3008   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3009   if (state->includeStack.empty() || state->curlyCount>0) state->outputBuf->addArray(a.data(),a.length());
3010 }
3011 
3012 static inline void outputSpace(yyscan_t yyscanner,char c)
3013 {
3014   if (c=='\t') outputChar(yyscanner,'\t');
3015   else outputChar(yyscanner,' ');
3016 }
3017 
3018 static inline void outputSpaces(yyscan_t yyscanner,char *s)
3019 {
3020   const char *p=s;
3021   char c;
3022   while ((c=*p++))
3023   {
3024     if (c=='\t') outputChar(yyscanner,'\t');
3025     else outputChar(yyscanner,' ');
3026   }
3027 }
3028 
3029 static inline void extraSpacing(yyscan_t yyscanner)
3030 {
3031   struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3032   if (!yyextra->defContinue) return;
3033   for (int i=0; i< (int)yyleng; i++)
3034   {
3035     if (yytext[i] == '\t')
3036       yyextra->defExtraSpacing+='\t';
3037     else
3038       yyextra->defExtraSpacing+=' ';
3039   }
3040 }
3041 
3042 static QCString determineAbsoluteIncludeName(const QCString &curFile,const QCString &incFileName)
3043 {
3044   bool searchIncludes = Config_getBool(SEARCH_INCLUDES);
3045   QCString absIncFileName = incFileName;
3046   FileInfo fi(curFile.str());
3047   if (fi.exists())
3048   {
3049     QCString absName = QCString(fi.dirPath(TRUE))+"/"+incFileName;
3050     FileInfo fi2(absName.str());
3051     if (fi2.exists())
3052     {
3053       absIncFileName=fi2.absFilePath();
3054     }
3055     else if (searchIncludes) // search in INCLUDE_PATH as well
3056     {
3057       const StringVector &includePath = Config_getList(INCLUDE_PATH);
3058       for (const auto &incPath : includePath)
3059       {
3060         FileInfo fi3(incPath);
3061         if (fi3.exists() && fi3.isDir())
3062         {
3063           absName = QCString(fi3.absFilePath())+"/"+incFileName;
3064           //printf("trying absName=%s\n",qPrint(absName));
3065           FileInfo fi4(absName.str());
3066           if (fi4.exists())
3067           {
3068             absIncFileName=fi4.absFilePath();
3069             break;
3070           }
3071           //printf( "absIncFileName = %s\n", qPrint(absIncFileName) );
3072         }
3073       }
3074     }
3075     //printf( "absIncFileName = %s\n", qPrint(absIncFileName) );
3076   }
3077   return absIncFileName;
3078 }
3079 
3080 static void readIncludeFile(yyscan_t yyscanner,const QCString &inc)
3081 {
3082   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3083   uint i=0;
3084 
3085   // find the start of the include file name
3086   while (i<inc.length() &&
3087          (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
3088         ) i++;
3089   uint s=i;
3090 
3091   // was it a local include?
3092   bool localInclude = s>0 && inc.at(s-1)=='"';
3093 
3094   // find the end of the include file name
3095   while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
3096 
3097   if (s<inc.length() && i>s) // valid include file name found
3098   {
3099     // extract include path+name
3100     QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
3101 
3102     QCString dosExt = incFileName.right(4);
3103     if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb")
3104     {
3105       // skip imported binary files (e.g. M$ type libraries)
3106       return;
3107     }
3108 
3109     QCString oldFileName = state->fileName;
3110     FileDef *oldFileDef  = state->yyFileDef;
3111     int oldLineNr        = state->yyLineNr;
3112     //printf("Searching for '%s'\n",qPrint(incFileName));
3113 
3114     QCString absIncFileName = determineAbsoluteIncludeName(state->fileName,incFileName);
3115 
3116     // findFile will overwrite state->yyFileDef if found
3117     FileState *fs;
3118     bool alreadyProcessed = FALSE;
3119     //printf("calling findFile(%s)\n",qPrint(incFileName));
3120     if ((fs=findFile(yyscanner,incFileName,localInclude,alreadyProcessed))) // see if the include file can be found
3121     {
3122       {
3123         std::lock_guard<std::mutex> lock(g_globalDefineMutex);
3124         g_defineManager.addInclude(oldFileName.str(),absIncFileName.str());
3125       }
3126 
3127       //printf("Found include file!\n");
3128       if (Debug::isFlagSet(Debug::Preprocessor))
3129       {
3130         for (i=0;i<state->includeStack.size();i++)
3131         {
3132           Debug::print(Debug::Preprocessor,0,"  ");
3133         }
3134         Debug::print(Debug::Preprocessor,0,"#include %s: parsing...\n",qPrint(incFileName));
3135       }
3136 
3137       if (state->includeStack.empty() && oldFileDef)
3138       {
3139         PreIncludeInfo *ii = state->includeRelations.find(absIncFileName);
3140         if (ii==0)
3141         {
3142           bool ambig;
3143           FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
3144           state->includeRelations.add(
3145               absIncFileName,
3146               oldFileDef,
3147               ambig?nullptr:incFd,
3148               incFileName,
3149               localInclude,
3150               state->isImported
3151               );
3152         }
3153       }
3154 
3155       struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3156       fs->bufState = YY_CURRENT_BUFFER;
3157       fs->lineNr   = oldLineNr;
3158       fs->fileName = oldFileName;
3159       fs->curlyCount = state->curlyCount;
3160       state->curlyCount = 0;
3161       // push the state on the stack
3162       state->includeStack.emplace_back(fs);
3163       // set the scanner to the include file
3164 
3165       // Deal with file changes due to
3166       // #include's within { .. } blocks
3167       QCString lineStr(state->fileName.length()+20);
3168       lineStr.sprintf("# 1 \"%s\" 1\n",qPrint(state->fileName));
3169       outputString(yyscanner,lineStr);
3170 
3171       DBG_CTX((stderr,"Switching to include file %s\n",qPrint(incFileName)));
3172       state->expectGuard=TRUE;
3173       state->inputBuf   = &fs->fileBuf;
3174       state->inputBufPos=0;
3175       yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE, yyscanner),yyscanner);
3176     }
3177     else
3178     {
3179       if (alreadyProcessed) // if this header was already process we can just copy the stored macros
3180                            // in the local context
3181       {
3182         std::lock_guard<std::mutex> lock(g_globalDefineMutex);
3183         g_defineManager.addInclude(state->fileName.str(),absIncFileName.str());
3184         g_defineManager.retrieve(absIncFileName.str(),state->contextDefines);
3185       }
3186 
3187       if (state->includeStack.empty() && oldFileDef)
3188       {
3189         PreIncludeInfo *ii = state->includeRelations.find(absIncFileName);
3190         if (ii==0)
3191         {
3192           bool ambig;
3193           FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
3194           ii = state->includeRelations.add(absIncFileName,
3195               oldFileDef,
3196               ambig?0:incFd,
3197               incFileName,
3198               localInclude,
3199               state->isImported
3200               );
3201         }
3202       }
3203 
3204       if (Debug::isFlagSet(Debug::Preprocessor))
3205       {
3206         for (i=0;i<state->includeStack.size();i++)
3207         {
3208           Debug::print(Debug::Preprocessor,0,"  ");
3209         }
3210         if (alreadyProcessed)
3211         {
3212           Debug::print(Debug::Preprocessor,0,"#include %s: already processed! skipping...\n",qPrint(incFileName));
3213         }
3214         else
3215         {
3216           Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",qPrint(incFileName));
3217         }
3218         //printf("error: include file %s not found\n",yytext);
3219       }
3220       if (state->curlyCount>0 && !alreadyProcessed) // failed to find #include inside { ... }
3221       {
3222         warn(state->fileName,state->yyLineNr,"include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",qPrint(incFileName));
3223       }
3224     }
3225   }
3226 }
3227 
3228 /* ----------------------------------------------------------------- */
3229 
3230 static void startCondSection(yyscan_t yyscanner,const QCString &sectId)
3231 {
3232   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3233   //printf("startCondSection: skip=%d stack=%d\n",state->skip,state->condStack.size());
3234   CondParser prs;
3235   bool expResult = prs.parse(state->fileName.data(),state->yyLineNr,sectId.data());
3236   state->condStack.emplace(std::make_unique<preYY_CondCtx>(state->yyLineNr,sectId,state->skip));
3237   if (!expResult)
3238   {
3239     state->skip=TRUE;
3240   }
3241   //printf("  expResult=%d skip=%d\n",expResult,state->skip);
3242 }
3243 
3244 static void endCondSection(yyscan_t yyscanner)
3245 {
3246   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3247   if (state->condStack.empty())
3248   {
3249     warn(state->fileName,state->yyLineNr,"the \\endcond does not have a corresponding \\cond in this file");
3250     state->skip=FALSE;
3251   }
3252   else
3253   {
3254     const std::unique_ptr<preYY_CondCtx> &ctx = state->condStack.top();
3255     state->skip=ctx->skip;
3256     state->condStack.pop();
3257   }
3258   //printf("endCondSection: skip=%d stack=%d\n",state->skip,state->condStack.count());
3259 }
3260 
3261 static void forceEndCondSection(yyscan_t yyscanner)
3262 {
3263   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3264   while (!state->condStack.empty())
3265   {
3266     state->condStack.pop();
3267   }
3268   state->skip=FALSE;
3269 }
3270 
3271 static QCString escapeAt(const QCString &text)
3272 {
3273   QCString result;
3274   if (!text.isEmpty())
3275   {
3276     char c;
3277     const char *p=text.data();
3278     while ((c=*p++))
3279     {
3280       if (c=='@') result+="@@"; else result+=c;
3281     }
3282   }
3283   return result;
3284 }
3285 
3286 static char resolveTrigraph(char c)
3287 {
3288   switch (c)
3289   {
3290     case '=': return '#';
3291     case '/': return '\\';
3292     case '\'': return '^';
3293     case '(': return '[';
3294     case ')': return ']';
3295     case '!': return '|';
3296     case '<': return '{';
3297     case '>': return '}';
3298     case '-': return '~';
3299   }
3300   return '?';
3301 }
3302 
3303 /*@ ----------------------------------------------------------------------------
3304  */
3305 
3306 static int getNextChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos)
3307 {
3308   //printf("getNextChar(%s,%s,%d)\n",qPrint(expr),rest ? rest->data() : 0,pos);
3309   if (pos<expr.length())
3310   {
3311     //printf("%c=expr()\n",expr.at(pos));
3312     return expr.at(pos++);
3313   }
3314   else if (rest && !rest->isEmpty())
3315   {
3316     int cc=rest->at(0);
3317     *rest=rest->right(rest->length()-1);
3318     //printf("%c=rest\n",cc);
3319     return cc;
3320   }
3321   else
3322   {
3323     int cc=yyinput(yyscanner);
3324     //printf("%d=yyinput() %d\n",cc,EOF);
3325     return cc;
3326   }
3327 }
3328 
3329 static int getCurrentChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint pos)
3330 {
3331   //printf("getCurrentChar(%s,%s,%d)\n",qPrint(expr),rest ? rest->data() : 0,pos);
3332   if (pos<expr.length())
3333   {
3334     //printf("%c=expr()\n",expr.at(pos));
3335     return expr.at(pos);
3336   }
3337   else if (rest && !rest->isEmpty())
3338   {
3339     int cc=rest->at(0);
3340     //printf("%c=rest\n",cc);
3341     return cc;
3342   }
3343   else
3344   {
3345     int cc=yyinput(yyscanner);
3346     returnCharToStream(yyscanner,(char)cc);
3347     //printf("%c=yyinput()\n",cc);
3348     return cc;
3349   }
3350 }
3351 
3352 static void unputChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint &pos,char c)
3353 {
3354   //printf("unputChar(%s,%s,%d,%c)\n",qPrint(expr),rest ? rest->data() : 0,pos,c);
3355   if (pos<expr.length())
3356   {
3357     pos++;
3358   }
3359   else if (rest)
3360   {
3361     //printf("Prepending to rest!\n");
3362     char cs[2];cs[0]=c;cs[1]='\0';
3363     rest->prepend(cs);
3364   }
3365   else
3366   {
3367     //unput(c);
3368     returnCharToStream(yyscanner,c);
3369   }
3370   //printf("result: unputChar(%s,%s,%d,%c)\n",qPrint(expr),rest ? rest->data() : 0,pos,c);
3371 }
3372 
3373 /** Returns a reference to a Define object given its name or 0 if the Define does
3374  *  not exist.
3375  */
3376 static Define *isDefined(yyscan_t yyscanner,const QCString &name)
3377 {
3378   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3379 
3380   bool undef = false;
3381   auto findDefine = [&undef,&name](DefineMap &map)
3382   {
3383     Define *d=0;
3384     auto it = map.find(name.str());
3385     if (it!=map.end())
3386     {
3387       d = &it->second;
3388       if (d->undef)
3389       {
3390         undef=true;
3391         d=0;
3392       }
3393     }
3394     return d;
3395   };
3396 
3397   Define *def = findDefine(state->localDefines);
3398   if (def==0 && !undef)
3399   {
3400     def = findDefine(state->contextDefines);
3401   }
3402   return def;
3403 }
3404 
3405 static void initPredefined(yyscan_t yyscanner,const QCString &fileName)
3406 {
3407   YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3408 
3409   // add predefined macros
3410   const StringVector &predefList = Config_getList(PREDEFINED);
3411   for (const auto &ds : predefList)
3412   {
3413     size_t i_equals=ds.find('=');
3414     size_t i_obrace=ds.find('(');
3415     size_t i_cbrace=ds.find(')');
3416     bool nonRecursive = i_equals!=std::string::npos && i_equals>0 && ds[i_equals-1]==':';
3417 
3418     if ((i_obrace==0) || (i_equals==0) || (i_equals==1 && ds[i_equals-1]==':'))
3419     {
3420       continue; // no define name
3421     }
3422 
3423     if (i_obrace<i_equals && i_cbrace<i_equals &&
3424         i_obrace!=std::string::npos && i_cbrace!=std::string::npos &&
3425         i_obrace<i_cbrace
3426        ) // predefined function macro definition
3427     {
3428       static const reg::Ex reId(R"(\a\w*)");
3429       std::map<std::string,int> argMap;
3430       std::string args  = ds.substr(i_obrace+1,i_cbrace-i_obrace-1); // part between ( and )
3431       bool   hasVarArgs = args.find("...")!=std::string::npos;
3432       //printf("predefined function macro '%s'\n",ds.c_str());
3433       int count = 0;
3434       reg::Iterator arg_it(args,reId,0);
3435       reg::Iterator arg_end;
3436       // gather the formal arguments in a dictionary
3437       for (; arg_it!=arg_end; ++arg_it)
3438       {
3439         argMap.emplace(arg_it->str(),count++);
3440       }
3441       if (hasVarArgs) // add the variable argument if present
3442       {
3443         argMap.emplace("__VA_ARGS__",count++);
3444       }
3445 
3446       // strip definition part
3447       std::string definition;
3448       std::string in=ds.substr(i_equals+1);
3449       reg::Iterator re_it(in,reId);
3450       reg::Iterator re_end;
3451       size_t i=0;
3452       // substitute all occurrences of formal arguments by their
3453       // corresponding markers
3454       for (; re_it!=re_end; ++re_it)
3455       {
3456         const auto &match = *re_it;
3457         size_t pi = match.position();
3458         size_t l  = match.length();
3459         if (pi>i) definition+=in.substr(i,pi-i);
3460 
3461         auto it = argMap.find(match.str());
3462         if (it!=argMap.end())
3463         {
3464           int argIndex = it->second;
3465           QCString marker;
3466           marker.sprintf(" @%d ",argIndex);
3467           definition+=marker.str();
3468         }
3469         else
3470         {
3471           definition+=match.str();
3472         }
3473         i=pi+l;
3474       }
3475       definition+=in.substr(i);
3476 
3477       // add define definition to the dictionary of defines for this file
3478       std::string dname = ds.substr(0,i_obrace);
3479       if (!dname.empty())
3480       {
3481         Define def;
3482         def.name         = dname;
3483         def.definition   = definition;
3484         def.nargs        = count;
3485         def.isPredefined = TRUE;
3486         def.nonRecursive = nonRecursive;
3487         def.fileDef      = state->yyFileDef;
3488         def.fileName     = fileName;
3489         def.varArgs      = hasVarArgs;
3490         state->contextDefines.insert(std::make_pair(def.name.str(),def));
3491 
3492         //printf("#define '%s' '%s' #nargs=%d hasVarArgs=%d\n",
3493         //  qPrint(def.name),qPrint(def.definition),def.nargs,def.varArgs);
3494       }
3495     }
3496     else if (!ds.empty()) // predefined non-function macro definition
3497     {
3498       //printf("predefined normal macro '%s'\n",ds.c_str());
3499       Define def;
3500       if (i_equals==std::string::npos) // simple define without argument
3501       {
3502         def.name = ds;
3503         def.definition = "1"; // substitute occurrences by 1 (true)
3504       }
3505       else // simple define with argument
3506       {
3507         int ine=static_cast<int>(i_equals) - (nonRecursive ? 1 : 0);
3508         def.name = ds.substr(0,ine);
3509         def.definition = ds.substr(i_equals+1);
3510       }
3511       if (!def.name.isEmpty())
3512       {
3513         def.nargs = -1;
3514         def.isPredefined = TRUE;
3515         def.nonRecursive = nonRecursive;
3516         def.fileDef      = state->yyFileDef;
3517         def.fileName     = fileName;
3518         state->contextDefines.insert(std::make_pair(def.name.str(),def));
3519       }
3520     }
3521   }
3522 }
3523 
3524 ///////////////////////////////////////////////////////////////////////////////////////////////
3525 
3526 struct Preprocessor::Private
3527 {
3528   yyscan_t yyscanner;
3529   preYY_state state;
3530 };
3531 
3532 void Preprocessor::addSearchDir(const QCString &dir)
3533 {
3534   YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner);
3535   FileInfo fi(dir.str());
3536   if (fi.isDir()) state->pathList.push_back(fi.absFilePath());
3537 }
3538 
3539 Preprocessor::Preprocessor() : p(std::make_unique<Private>())
3540 {
3541   preYYlex_init_extra(&p->state,&p->yyscanner);
3542   addSearchDir(".");
3543 }
3544 
3545 Preprocessor::~Preprocessor()
3546 {
3547   preYYlex_destroy(p->yyscanner);
3548 }
3549 
3550 void Preprocessor::processFile(const QCString &fileName,BufStr &input,BufStr &output)
3551 {
3552 //  printf("Preprocessor::processFile(%s)\n",fileName);
3553   yyscan_t yyscanner = p->yyscanner;
3554   YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner);
3555   struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3556 
3557 #ifdef FLEX_DEBUG
3558   preYYset_debug(1,yyscanner);
3559 #endif
3560 
3561   printlex(yy_flex_debug, TRUE, __FILE__, qPrint(fileName));
3562   uint orgOffset=output.curPos();
3563   //printf("##########################\n%s\n####################\n",
3564   //    qPrint(input));
3565 
3566   state->macroExpansion = Config_getBool(MACRO_EXPANSION);
3567   state->expandOnlyPredef = Config_getBool(EXPAND_ONLY_PREDEF);
3568   state->skip=FALSE;
3569   state->curlyCount=0;
3570   state->nospaces=FALSE;
3571   state->inputBuf=&input;
3572   state->inputBufPos=0;
3573   state->outputBuf=&output;
3574   state->includeStack.clear();
3575   state->expandedDict.clear();
3576   state->contextDefines.clear();
3577   while (!state->condStack.empty()) state->condStack.pop();
3578 
3579   setFileName(yyscanner,fileName);
3580 
3581   state->inputFileDef = state->yyFileDef;
3582   //yyextra->defineManager.startContext(state->fileName);
3583 
3584   initPredefined(yyscanner,fileName);
3585 
3586   state->yyLineNr = 1;
3587   state->yyColNr  = 1;
3588   state->ifcount  = 0;
3589 
3590   BEGIN( Start );
3591 
3592   state->expectGuard = guessSection(fileName)==Entry::HEADER_SEC;
3593   state->guardName.resize(0);
3594   state->lastGuardName.resize(0);
3595   state->guardExpr.resize(0);
3596 
3597   preYYlex(yyscanner);
3598 
3599   while (!state->condStack.empty())
3600   {
3601     const std::unique_ptr<preYY_CondCtx> &ctx = state->condStack.top();
3602     QCString sectionInfo = " ";
3603     if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",qPrint(ctx->sectionId.stripWhiteSpace()));
3604     warn(fileName,ctx->lineNr,"Conditional section%sdoes not have "
3605         "a corresponding \\endcond command within this file.",qPrint(sectionInfo));
3606     state->condStack.pop();
3607   }
3608   // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829)
3609   forceEndCondSection(yyscanner);
3610 
3611   if (Debug::isFlagSet(Debug::Preprocessor))
3612   {
3613     std::lock_guard<std::mutex> lock(g_debugMutex);
3614     char *orgPos=output.data()+orgOffset;
3615     char *newPos=output.data()+output.curPos();
3616     Debug::print(Debug::Preprocessor,0,"Preprocessor output of %s (size: %d bytes):\n",qPrint(fileName),newPos-orgPos);
3617     int line=1;
3618     Debug::print(Debug::Preprocessor,0,"---------\n");
3619     if (!Debug::isFlagSet(Debug::NoLineNo)) Debug::print(Debug::Preprocessor,0,"00001 ");
3620     while (orgPos<newPos)
3621     {
3622       putchar(*orgPos);
3623       if (*orgPos=='\n' && !Debug::isFlagSet(Debug::NoLineNo)) Debug::print(Debug::Preprocessor,0,"%05d ",++line);
3624       orgPos++;
3625     }
3626     Debug::print(Debug::Preprocessor,0,"\n---------\n");
3627     if (yyextra->contextDefines.size()>0)
3628     {
3629       Debug::print(Debug::Preprocessor,0,"Macros accessible in this file (%s):\n", qPrint(fileName));
3630       Debug::print(Debug::Preprocessor,0,"---------\n");
3631       for (auto &kv : yyextra->contextDefines)
3632       {
3633         Debug::print(Debug::Preprocessor,0,"%s ",qPrint(kv.second.name));
3634       }
3635       for (auto &kv : yyextra->localDefines)
3636       {
3637         Debug::print(Debug::Preprocessor,0,"%s ",qPrint(kv.second.name));
3638       }
3639       Debug::print(Debug::Preprocessor,0,"\n---------\n");
3640     }
3641     else
3642     {
3643       Debug::print(Debug::Preprocessor,0,"No macros accessible in this file (%s).\n", qPrint(fileName));
3644     }
3645   }
3646 
3647   {
3648     std::lock_guard<std::mutex> lock(g_updateGlobals);
3649     for (const auto &inc : state->includeRelations)
3650     {
3651       if (inc->fromFileDef)
3652       {
3653         inc->fromFileDef->addIncludeDependency(inc->toFileDef,inc->includeName,inc->local,inc->imported);
3654       }
3655       if (inc->toFileDef && inc->fromFileDef)
3656       {
3657         inc->toFileDef->addIncludedByDependency(inc->fromFileDef,inc->fromFileDef->docName(),inc->local,inc->imported);
3658       }
3659     }
3660     // add the macro definition for this file to the global map
3661     Doxygen::macroDefinitions.emplace(std::make_pair(state->fileName.str(),std::move(state->macroDefinitions)));
3662   }
3663 
3664   //yyextra->defineManager.endContext();
3665   printlex(yy_flex_debug, FALSE, __FILE__, qPrint(fileName));
3666 //  printf("Preprocessor::processFile(%s) finished\n",fileName);
3667 }
3668 
3669 #if USE_STATE2STRING
3670 #include "pre.l.h"
3671 #endif
3672