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