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