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