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