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:1336
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:3905
static void setCaseDone(yyscan_t yyscanner, bool value)
Definition pre.l:2314
static void addMacroDefinition(yyscan_t yyscanner)
Definition pre.l:3625
static void decrLevel(yyscan_t yyscanner)
Definition pre.l:2279
static void addDefine(yyscan_t yyscanner)
Definition pre.l:3596
static void determineBlockName(yyscan_t yyscanner)
Definition pre.l:3717
static void incrLevel(yyscan_t yyscanner)
Definition pre.l:2272
static QCString expandMacro(yyscan_t yyscanner, const QCString &name)
Definition pre.l:3553
static void outputSpaces(yyscan_t yyscanner, char *s)
Definition pre.l:3693
static void endCondSection(yyscan_t yyscanner)
Definition pre.l:3919
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:4067
static void outputString(yyscan_t yyscanner, const QCString &s)
Definition pre.l:3681
static void setFileName(yyscan_t yyscanner, const QCString &name)
Definition pre.l:2251
static std::mutex g_globalDefineMutex
Definition pre.l:233
static void outputChar(yyscan_t yyscanner, char c)
Definition pre.l:3669
static QCString extractTrailingComment(const QCString &s)
Definition pre.l:2452
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
Definition pre.l:2230
static char resolveTrigraph(char c)
Definition pre.l:3977
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:3567
static void readIncludeFile(yyscan_t yyscanner, const QCString &inc)
Definition pre.l:3750
static yy_size_t getFenceSize(char *txt, yy_size_t leng)
Definition pre.l:2240
static std::mutex g_updateGlobals
Definition pre.l:234
static bool otherCaseDone(yyscan_t yyscanner)
Definition pre.l:2300
static void outputArray(yyscan_t yyscanner, const char *a, yy_size_t len)
Definition pre.l:3675
static void extraSpacing(yyscan_t yyscanner)
Definition pre.l:3704
static const char * getLexerFILE()
Definition pre.l:356
static QCString escapeAt(const QCString &text)
Definition pre.l:3962
static bool computeExpression(yyscan_t yyscanner, const QCString &expr)
Definition pre.l:3534
static void outputSpace(yyscan_t yyscanner, char c)
Definition pre.l:3687
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->defText+=yytext;
1498 yyextra->defLitText+=yytext;
1499 yyextra->lastCContext=YY_START;
1500 yyextra->commentCount=1;
1501 BEGIN(CopyCComment);
1502 }
1503<DefineText>{CPPC}[!/]? {
1504 outputArray(yyscanner,yytext,yyleng);
1505 yyextra->lastCPPContext=YY_START;
1506 yyextra->defLitText+=' ';
1507 BEGIN(SkipCPPComment);
1508 }
1509<SkipCComment>[/]?{CCE} {
1510 if (yytext[0]=='/') outputChar(yyscanner,'/');
1511 outputChar(yyscanner,'*');outputChar(yyscanner,'/');
1512 if (--yyextra->commentCount<=0)
1513 {
1514 if (yyextra->lastCContext==Start)
1515 // small hack to make sure that ^... rule will
1516 // match when going to Start... Example: "/*...*/ some stuff..."
1517 {
1518 YY_CURRENT_BUFFER->yy_at_bol=1;
1519 }
1520 BEGIN(yyextra->lastCContext);
1521 }
1522 }
1523<SkipCComment>{CPPC}("/")* {
1524 outputArray(yyscanner,yytext,yyleng);
1525 }
1526<SkipCComment>{CCS} {
1527 outputChar(yyscanner,'/');outputChar(yyscanner,'*');
1528 //yyextra->commentCount++;
1529 }
1530<SkipCond>{CMD}{CMD} { }
1531<SkipCond>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
1532 bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1533 if (!markdownSupport || !yyextra->isSpecialComment)
1534 {
1535 REJECT;
1536 }
1537 else
1538 {
1539 yyextra->fenceChar='~';
1540 yyextra->fenceSize=(int)getFenceSize(yytext,yyleng);
1541 BEGIN(SkipCondVerbatim);
1542 }
1543 }
1544<SkipCond>^({B}*"*"+)?{B}{0,3}"```"[`]* {
1545 bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1546 if (!markdownSupport || !yyextra->isSpecialComment)
1547 {
1548 REJECT;
1549 }
1550 else
1551 {
1552 yyextra->fenceChar='`';
1553 yyextra->fenceSize=(int)getFenceSize(yytext,yyleng);
1554 BEGIN(SkipCondVerbatim);
1555 }
1556 }
1557<SkipCComment>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
1558 bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1559 if (!markdownSupport || !yyextra->isSpecialComment)
1560 {
1561 REJECT;
1562 }
1563 else
1564 {
1565 outputArray(yyscanner,yytext,yyleng);
1566 yyextra->fenceChar='~';
1567 yyextra->fenceSize=(int)getFenceSize(yytext,yyleng);
1568 BEGIN(SkipVerbatim);
1569 }
1570 }
1571<SkipCComment>^({B}*"*"+)?{B}{0,3}"```"[`]* {
1572 bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1573 if (!markdownSupport || !yyextra->isSpecialComment)
1574 {
1575 REJECT;
1576 }
1577 else
1578 {
1579 outputArray(yyscanner,yytext,yyleng);
1580 yyextra->fenceChar='`';
1581 yyextra->fenceSize=(int)getFenceSize(yytext,yyleng);
1582 BEGIN(SkipVerbatim);
1583 }
1584 }
1585<SkipCComment>{CMD}{VERBATIM_LINE} |
1586<SkipCComment>{CMD}{LITERAL_BLOCK} { // escaped command
1587 outputArray(yyscanner,yytext,yyleng);
1588 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1589 }
1590<SkipCComment>{VERBATIM_LINE}.*/\n { // normal command
1591 outputArray(yyscanner,yytext,yyleng);
1592 }
1593<SkipCComment>{LITERAL_BLOCK} { // normal block command
1594 outputArray(yyscanner,yytext,yyleng);
1595 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1596 if (yyextra->isSpecialComment)
1597 {
1598 determineBlockName(yyscanner);
1599 BEGIN(SkipVerbatim);
1600 }
1601 }
1602<SkipCond>{CMD}{CMD}"cond"[ \t]+ {}// escaped cond command
1603<SkipCond>{CMD}"cond"/\n |
1604<SkipCond>{CMD}"cond"[ \t]+ { // cond command in a skipped cond section, this section has to be skipped as well
1605 // but has to be recorded to match the endcond command
1606 startCondSection(yyscanner," ");
1607 }
static void startCondSection(yyscan_t yyscanner, const QCString &sectId)
1608<SkipCComment>"{"[ \t]*"@code"/[ \t\n] {
1609 outputArray(yyscanner,"@iliteral{code}",15);
1610 yyextra->javaBlock=1;
1611 BEGIN(JavaDocVerbatimCode);
1612 }
1613<SkipCComment>"{"[ \t]*"@literal"/[ \t\n] {
1614 outputArray(yyscanner,"@iliteral",9);
1615 yyextra->javaBlock=1;
1616 BEGIN(JavaDocVerbatimCode);
1617 }
1618<SkipCComment,SkipCPPComment>{CMD}{CMD}"cond"[ \t\n]+ { // escaped cond command
1619 outputArray(yyscanner,yytext,yyleng);
1620 }
1621<SkipCPPComment>{CMD}"cond"[ \t]+ { // conditional section
1622 yyextra->ccomment=TRUE;
1623 yyextra->condCtx=YY_START;
1624 BEGIN(CondLineCpp);
1625 }
1626<SkipCComment>{CMD}"cond"[ \t]+ { // conditional section
1627 yyextra->ccomment=FALSE;
1628 yyextra->condCtx=YY_START;
1629 BEGIN(CondLineC);
1630 }
1631<CondLineC,CondLineCpp>[!()&| \ta-z_A-Z0-9\x80-\xFF.\-]+ {
1632 startCondSection(yyscanner,yytext);
1633 if (yyextra->skip)
1634 {
1635 if (YY_START==CondLineC)
1636 {
1637 // end C comment
1638 outputArray(yyscanner,"*/",2);
1639 yyextra->ccomment=TRUE;
1640 }
1641 else
1642 {
1643 yyextra->ccomment=FALSE;
1644 }
1645 BEGIN(SkipCond);
1646 }
1647 else
1648 {
1649 BEGIN(yyextra->condCtx);
1650 }
1651 }
1652<CondLineC,CondLineCpp>. { // non-guard character
1653 unput(*yytext);
1654 startCondSection(yyscanner," ");
1655 if (yyextra->skip)
1656 {
1657 if (YY_START==CondLineC)
1658 {
1659 // end C comment
1660 outputArray(yyscanner,"*/",2);
1661 yyextra->ccomment=TRUE;
1662 }
1663 else
1664 {
1665 yyextra->ccomment=FALSE;
1666 }
1667 BEGIN(SkipCond);
1668 }
1669 else
1670 {
1671 BEGIN(yyextra->condCtx);
1672 }
1673 }
1674<SkipCComment,SkipCPPComment>{CMD}"cond"{WSopt}/\n { // no guard
1675 if (YY_START==SkipCComment)
1676 {
1677 yyextra->ccomment=TRUE;
1678 // end C comment
1679 outputArray(yyscanner,"*/",2);
1680 }
1681 else
1682 {
1683 yyextra->ccomment=FALSE;
1684 }
1685 yyextra->condCtx=YY_START;
1686 yyextra->condGuardCount=0;
1687 startCondSection(yyscanner," ");
1688 BEGIN(SkipCond);
1689 }
1690<SkipCond>\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
1691<SkipCond>{VERBATIM_LINE}.*/\n { }
1692<SkipCond>{LITERAL_BLOCK} {
1693 auto numNLs = QCString(yytext).contains('\n');
1694 yyextra->yyLineNr+=numNLs;
1695 for (int i = 0; i < numNLs; i++) outputChar(yyscanner,'\n');
1696 determineBlockName(yyscanner);
1697 BEGIN(SkipCondVerbatim);
1698 }
1699
1700<SkipCond>. { }
1701<SkipCond>"#if"("def")? { yyextra->condGuardCount++; }
1702<SkipCond>"#endif" { yyextra->condGuardCount--; }
1703<SkipCond>[^\/\!*\\@\n#]+ { }
1704<SkipCond>{CPPC}[/!] { yyextra->ccomment=FALSE; }
1705<SkipCond>{CCS}[*!] { yyextra->ccomment=TRUE; }
1706<SkipCond,SkipCComment,SkipCPPComment>{CMD}{CMD}"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1707 if (!yyextra->skip)
1708 {
1709 outputArray(yyscanner,yytext,yyleng);
1710 }
1711 }
1712<SkipCond>{CMD}"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1713 bool oldSkip = yyextra->skip;
1714 endCondSection(yyscanner);
1715 if (oldSkip && !yyextra->skip)
1716 {
1717 if (yyextra->ccomment)
1718 {
1719 outputArray(yyscanner,"/** ",4); // */
1720 }
1721 BEGIN(yyextra->condCtx);
1722 }
1723 }
static void endCondSection(yyscan_t yyscanner)
1724<SkipCComment,SkipCPPComment>{CMD}"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1725 bool oldSkip = yyextra->skip;
1726 endCondSection(yyscanner);
1727 if (oldSkip && !yyextra->skip)
1728 {
1729 BEGIN(yyextra->condCtx);
1730 }
1731 }
1732<SkipCondVerbatim>{LITERAL_BLOCK_END} { /* end of verbatim block */
1733 if (yytext[1]=='f' && yyextra->blockName==&yytext[2])
1734 {
1735 BEGIN(SkipCond);
1736 }
1737 else if (&yytext[4]==yyextra->blockName)
1738 {
1739 BEGIN(SkipCond);
1740 }
1741 }
1742<SkipVerbatim>{LITERAL_BLOCK_END} { /* end of verbatim block */
1743 outputArray(yyscanner,yytext,yyleng);
1744 if (yytext[1]=='f' && yyextra->blockName==&yytext[2])
1745 {
1746 BEGIN(SkipCComment);
1747 }
1748 else if (&yytext[4]==yyextra->blockName)
1749 {
1750 BEGIN(SkipCComment);
1751 }
1752 }
1753<SkipCondVerbatim>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
1754 if (yyextra->fenceSize==getFenceSize(yytext,yyleng) && yyextra->fenceChar=='~')
1755 {
1756 BEGIN(SkipCond);
1757 }
1758 }
1759<SkipCondVerbatim>^({B}*"*"+)?{B}{0,3}"```"[`]* {
1760 if (yyextra->fenceSize==getFenceSize(yytext,yyleng) && yyextra->fenceChar=='`')
1761 {
1762 BEGIN(SkipCond);
1763 }
1764 }
1765<SkipVerbatim>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
1766 outputArray(yyscanner,yytext,yyleng);
1767 if (yyextra->fenceSize==getFenceSize(yytext,yyleng) && yyextra->fenceChar=='~')
1768 {
1769 BEGIN(SkipCComment);
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<SkipCondVerbatim>{CCE}|{CCS} { }
1780<SkipVerbatim>{CCE}|{CCS} {
1781 outputArray(yyscanner,yytext,yyleng);
1782 }
1783<JavaDocVerbatimCode>"{" {
1784 if (yyextra->javaBlock==0)
1785 {
1786 REJECT;
1787 }
1788 else
1789 {
1790 yyextra->javaBlock++;
1791 outputArray(yyscanner,yytext,(int)yyleng);
1792 }
1793 }
1794<JavaDocVerbatimCode>"}" {
1795 if (yyextra->javaBlock==0)
1796 {
1797 REJECT;
1798 }
1799 else
1800 {
1801 yyextra->javaBlock--;
1802 if (yyextra->javaBlock==0)
1803 {
1804 outputArray(yyscanner," @endiliteral ",14);
1805 BEGIN(SkipCComment);
1806 }
1807 else
1808 {
1809 outputArray(yyscanner,yytext,(int)yyleng);
1810 }
1811 }
1812 }
1813<JavaDocVerbatimCode>\n { /* new line in verbatim block */
1814 outputArray(yyscanner,yytext,(int)yyleng);
1815 }
1816<JavaDocVerbatimCode>. { /* any other character */
1817 outputArray(yyscanner,yytext,(int)yyleng);
1818 }
1819<SkipCondVerbatim>[^{*\\@\x06~`\n\/]+ { }
1820<SkipCComment,SkipVerbatim>[^{*\\@\x06~`\n\/]+ {
1821 outputArray(yyscanner,yytext,yyleng);
1822 }
1823<SkipCComment,SkipVerbatim,SkipCondVerbatim>\n {
1824 yyextra->yyLineNr++;
1825 outputChar(yyscanner,'\n');
1826 }
1827<SkipCondVerbatim>. { }
1828<SkipCComment,SkipVerbatim>. {
1829 outputChar(yyscanner,*yytext);
1830 }
1831<CopyCComment>[^*a-z_A-Z\x80-\xFF\n]*[^*a-z_A-Z\x80-\xFF\\\n] {
1832 yyextra->defLitText+=yytext;
1833 yyextra->defText+=escapeAt(yytext);
1834 }
1835<CopyCComment>\\‍[\r]?\n {
1836 yyextra->defLitText+=yytext;
1837 yyextra->defText+=" ";
1838 yyextra->yyLineNr++;
1839 yyextra->yyMLines++;
1840 }
1841<CopyCComment>{CCE} {
1842 yyextra->defLitText+=yytext;
1843 yyextra->defText+=yytext;
1844 BEGIN(yyextra->lastCContext);
1845 }
1846<CopyCComment>\n {
1847 yyextra->yyLineNr++;
1848 yyextra->defLitText+=yytext;
1849 yyextra->defText+=' ';
1850 }
1851<RemoveCComment>{CCE}{B}*"#" { // see bug 594021 for a usecase for this rule
1852 if (yyextra->lastCContext==SkipCPPBlock)
1853 {
1854 BEGIN(SkipCommand);
1855 }
1856 else
1857 {
1858 REJECT;
1859 }
1860 }
1861<RemoveCComment>{CCE} { BEGIN(yyextra->lastCContext); }
1862<RemoveCComment>{CPPC}
1863<RemoveCComment>{CCS}
1864<RemoveCComment>[^*\x06\n]+
1865<RemoveCComment>\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
1866<RemoveCComment>.
1867<SkipCPPComment>[^\n\/\\@]+ {
1868 outputArray(yyscanner,yytext,yyleng);
1869 }
1870<SkipCPPComment,RemoveCPPComment>\n {
1871 unput(*yytext);
1872 BEGIN(yyextra->lastCPPContext);
1873 }
1874<SkipCPPComment>{CCS} {
1875 outputChar(yyscanner,'/');outputChar(yyscanner,'*');
1876 }
1877<SkipCPPComment>{CPPC} {
1878 outputChar(yyscanner,'/');outputChar(yyscanner,'/');
1879 }
1880<SkipCPPComment>[^\x06\@\\\n]+ {
1881 outputArray(yyscanner,yytext,yyleng);
1882 }
1883<SkipCPPComment>. {
1884 outputChar(yyscanner,*yytext);
1885 }
1886<RemoveCPPComment>{CCS}
1887<RemoveCPPComment>{CPPC}
1888<RemoveCPPComment>[^\x06\n]+
1889<RemoveCPPComment>.
1890<DefineText>"__VA_OPT__("{B}*"##" {
1891 warn(yyextra->fileName,yyextra->yyLineNr,
1892 "'##' may not appear at the beginning of a __VA_OPT__()",
1893 yyextra->defName,yyextra->defLitText.stripWhiteSpace());
1894 yyextra->defText+="__VA_OPT__(";
1895 yyextra->defLitText+="__VA_OPT__(";
1896 }
#define warn(file, line, fmt,...)
Definition message.h:97
1897<DefineText>"#"/"__VA_OPT__" {
1898 yyextra->defText+=yytext;
1899 yyextra->defLitText+=yytext;
1900 }
1901<DefineText>"#"/{IDSTART} {
1902 outputChar(yyscanner,' ');
1903 yyextra->quoteArg=TRUE;
1904 yyextra->idStart=true;
1905 yyextra->defLitText+=yytext;
1906 }
1907<DefineText,CopyCComment>{ID} {
1908 yyextra->defLitText+=yytext;
1909 if (YY_START == DefineText) outputSpaces(yyscanner,yytext);
1910 if (yyextra->quoteArg)
1911 {
1912 yyextra->defText+="\"";
1913 }
1914 if (yyextra->defArgs>0)
1915 {
1916 auto it = yyextra->argMap.find(yytext);
1917 if (it!=yyextra->argMap.end())
1918 {
1919 int n = it->second;
1920 yyextra->defText+='@';
1921 yyextra->defText+=QCString().setNum(n);
1922 }
1923 else
1924 {
1925 if (yyextra->idStart)
1926 {
1927 warn(yyextra->fileName,yyextra->yyLineNr,
1928 "'#' is not followed by a macro parameter '{}': '{}'",
1929 yyextra->defName,yyextra->defLitText.stripWhiteSpace());
1930 }
1931 yyextra->defText+=yytext;
1932 }
1933 }
1934 else
1935 {
1936 yyextra->defText+=yytext;
1937 }
1938 if (yyextra->quoteArg)
1939 {
1940 yyextra->defText+="\"";
1941 }
1942 yyextra->quoteArg=FALSE;
1943 yyextra->idStart=false;
1944 }
QCString & setNum(short n)
Definition qcstring.h:459
1945<CopyCComment>. {
1946 yyextra->defLitText+=yytext;
1947 yyextra->defText+=yytext;
1948 }
1949<DefineText>\\‍[\r]?\n {
1950 yyextra->defLitText+=yytext;
1951 outputChar(yyscanner,'\\');
1952 outputChar(yyscanner,'\n');
1953 yyextra->defText += ' ';
1954 yyextra->yyLineNr++;
1955 yyextra->yyMLines++;
1956 }
1957<DefineText>\n {
1958 QCString comment=extractTrailingComment(yyextra->defLitText);
1959 yyextra->defText = yyextra->defText.stripWhiteSpace();
1960 if (yyextra->defText.startsWith("##"))
1961 {
1962 warn(yyextra->fileName,yyextra->yyLineNr,
1963 "'##' cannot occur at the beginning of a macro definition '{}': '{}'",
1964 yyextra->defName,yyextra->defLitText.stripWhiteSpace());
1965 }
1966 else if (yyextra->defText.endsWith("##"))
1967 {
1968 warn(yyextra->fileName,yyextra->yyLineNr,
1969 "'##' cannot occur at the end of a macro definition '{}': '{}'",
1970 yyextra->defName,yyextra->defLitText.stripWhiteSpace());
1971 }
1972 else if (yyextra->defText.endsWith("#"))
1973 {
1974 warn(yyextra->fileName,yyextra->yyLineNr,
1975 "expected formal parameter after # in macro definition '{}': '{}'",
1976 yyextra->defName,yyextra->defLitText.stripWhiteSpace());
1977 }
1978 if (!comment.isEmpty())
1979 {
1980 outputString(yyscanner,comment);
1981 yyextra->defLitText=yyextra->defLitText.left(yyextra->defLitText.length()-comment.length()-1);
1982 }
1983 outputChar(yyscanner,'\n');
1984 yyextra->defLitText+=yytext;
1985 Define *def=nullptr;
1986 //printf("Define name='%s' text='%s' litTexti='%s'\n",qPrint(yyextra->defName),qPrint(yyextra->defText),qPrint(yyextra->defLitText));
1987 if (yyextra->includeStack.empty() || yyextra->curlyCount>0)
1988 {
1989 addMacroDefinition(yyscanner);
1990 }
1991 def=isDefined(yyscanner,yyextra->defName);
1992 if (def==0) // new define
1993 {
1994 //printf("new define '%s'!\n",qPrint(yyextra->defName));
1995 addDefine(yyscanner);
1996 }
1997 else if (def /*&& macroIsAccessible(def)*/)
1998 // name already exists
1999 {
2000 //printf("existing define!\n");
2001 //printf("define found\n");
2002 if (def->undef) // undefined name
2003 {
2004 def->undef = FALSE;
2005 def->name = yyextra->defName;
2006 def->definition = yyextra->defText.stripWhiteSpace();
2007 def->nargs = yyextra->defArgs;
2008 def->fileName = yyextra->fileName;
2009 def->lineNr = yyextra->yyLineNr-yyextra->yyMLines;
2010 def->columnNr = yyextra->yyColNr;
2011 }
2012 else
2013 {
2014 if (def->fileName != yyextra->fileName && !yyextra->expandOnlyPredef) addDefine(yyscanner);
2015 //printf("error: define %s is defined more than once!\n",qPrint(yyextra->defName));
2016 }
2017 }
2018 yyextra->argMap.clear();
2019 yyextra->yyLineNr++;
2020 yyextra->yyColNr=1;
2021 yyextra->lastGuardName.clear();
2022 BEGIN(Start);
2023 }
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
2024<DefineText>{B}* { outputString(yyscanner,yytext);
2025 yyextra->defText += ' ';
2026 yyextra->defLitText+=yytext;
2027 }
2028<DefineText>{B}*"##"{B}* { outputString(yyscanner,substitute(yytext,"##"," "));
2029 yyextra->defText += "##";
2030 yyextra->defLitText+=yytext;
2031 }
2032<DefineText>"@" { outputString(yyscanner,substitute(yytext,"@@"," "));
2033 yyextra->defText += "@@";
2034 yyextra->defLitText+=yytext;
2035 }
2036<DefineText>\" {
2037 outputChar(yyscanner,' ');
2038 yyextra->defText += *yytext;
2039 yyextra->defLitText+=yytext;
2040 if (!yyextra->insideComment)
2041 {
2042 BEGIN(SkipDoubleQuote);
2043 }
2044 }
2045<DefineText>{NUMBER} {
2046 outputSpaces(yyscanner,yytext);
2047 yyextra->defText += yytext;
2048 yyextra->defLitText+=yytext;
2049 }
2050<DefineText>\' {
2051 outputChar(yyscanner,' ');
2052 yyextra->defText += *yytext;
2053 yyextra->defLitText+=yytext;
2054 if (!yyextra->insideComment)
2055 {
2056 BEGIN(SkipSingleQuote);
2057 }
2058 }
2059<SkipDoubleQuote>{CPPC}[/]? { outputSpaces(yyscanner,yytext);
2060 yyextra->defText += yytext;
2061 yyextra->defLitText+=yytext;
2062 }
2063<SkipDoubleQuote>{CCS}[*]? { outputSpaces(yyscanner,yytext);
2064 yyextra->defText += yytext;
2065 yyextra->defLitText+=yytext;
2066 }
2067<SkipDoubleQuote>\" {
2068 outputChar(yyscanner,' ');
2069 yyextra->defText += *yytext;
2070 yyextra->defLitText+=yytext;
2071 BEGIN(DefineText);
2072 }
2073<SkipSingleQuote,SkipDoubleQuote>\\. {
2074 outputSpaces(yyscanner,yytext);
2075 yyextra->defText += yytext;
2076 yyextra->defLitText+=yytext;
2077 }
2078<SkipSingleQuote>\' {
2079 outputChar(yyscanner,' ');
2080 yyextra->defText += *yytext;
2081 yyextra->defLitText+=yytext;
2082 BEGIN(DefineText);
2083 }
2084<SkipDoubleQuote,SkipSingleQuote>. { outputSpace(yyscanner,yytext[0]);
2085 yyextra->defText += *yytext;
2086 yyextra->defLitText += *yytext;
2087 }
2088<DefineText>. { outputSpace(yyscanner,yytext[0]);
2089 yyextra->defText += *yytext;
2090 yyextra->defLitText += *yytext;
2091 }
2092<<EOF>> {
2093 TRACE("End of include file");
2094 //printf("Include stack depth=%d\n",yyextra->includeStack.size());
2095 if (yyextra->includeStack.empty())
2096 {
2097 TRACE("Terminating scanner");
2098 yyterminate();
2099 }
2100 else
2101 {
2102 if (!yyextra->levelGuard.empty())
2103 {
2104 if (yyextra->condGuardErrorLine!=0)
2105 {
2106 warn(yyextra->condGuardErrorFileName,yyextra->condGuardErrorLine,"{}",yyextra->condGuardErrorMessage);
2107 }
2108 else
2109 {
2110 warn(yyextra->fileName,yyextra->yyLineNr,"More #endif's than #if's found.");
2111 }
2112 }
2113 QCString toFileName = yyextra->fileName;
2114 const std::unique_ptr<FileState> &fs=yyextra->includeStack.back();
2115 //fileDefineCache->merge(yyextra->fileName,fs->fileName);
2116 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
2117 yy_switch_to_buffer( fs->bufState, yyscanner );
2118 yy_delete_buffer( oldBuf, yyscanner );
2119 yyextra->yyLineNr = fs->lineNr;
2120 //preYYin = fs->oldYYin;
2121 yyextra->inputBuf = fs->oldFileBuf;
2122 yyextra->inputBufPos = fs->oldFileBufPos;
2123 yyextra->curlyCount = fs->curlyCount;
2124 yyextra->levelGuard = fs->levelGuard;
2125 setFileName(yyscanner,fs->fileName);
2126 TRACE("switching to {}",yyextra->fileName);
2127
2128 // Deal with file changes due to
2129 // #include's within { .. } blocks
2130 QCString lineStr(15+yyextra->fileName.length(), QCString::ExplicitSize);
2131 lineStr.sprintf("# %d \"%s\" 2",yyextra->yyLineNr,qPrint(yyextra->fileName));
2132 outputString(yyscanner,lineStr);
2133
2134 yyextra->includeStack.pop_back();
2135
2136 {
2137 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
2138 // to avoid deadlocks we allow multiple threads to process the same header file.
2139 // The first one to finish will store the results globally. After that the
2140 // next time the same file is encountered, the stored data is used and the file
2141 // is not processed again.
2142 if (!g_defineManager.alreadyProcessed(toFileName.str()))
2143 {
2144 // now that the file is completely processed, prevent it from processing it again
2145 g_defineManager.addInclude(yyextra->fileName.str(),toFileName.str());
2146 g_defineManager.store(toFileName.str(),yyextra->localDefines);
2147 }
2148 else
2149 {
2151 {
2152 Debug::print(Debug::Preprocessor,0,"#include {}: was already processed by another thread! not storing data...\n",toFileName);
2153 }
2154 }
2155 }
2156 // move the local macros definitions for in this file to the translation unit context
2157 for (const auto &kv : yyextra->localDefines)
2158 {
2159 auto pair = yyextra->contextDefines.insert(kv);
2160 if (!pair.second) // define already in context -> replace with local version
2161 {
2162 yyextra->contextDefines.erase(pair.first);
2163 yyextra->contextDefines.insert(kv);
2164 }
2165 }
2166 yyextra->localDefines.clear();
2167 }
2168 }
@ 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
2169<*>{CCS}/{CCE} |
2170<*>{CCS}[*!]? {
2171 if (YY_START==SkipVerbatim || YY_START == SkipCondVerbatim || YY_START==SkipCond || YY_START==IDLquote || YY_START == PragmaOnce)
2172 {
2173 REJECT;
2174 }
2175 else
2176 {
2177 outputArray(yyscanner,yytext,yyleng);
2178 yyextra->lastCContext=YY_START;
2179 yyextra->commentCount=1;
2180 if (yyleng==3)
2181 {
2182 yyextra->isSpecialComment = true;
2183 yyextra->lastGuardName.clear(); // reset guard in case the #define is documented!
2184 }
2185 else
2186 {
2187 yyextra->isSpecialComment = false;
2188 }
2189 BEGIN(SkipCComment);
2190 }
2191 }
2192<*>{CPPC}[/!]? {
2193 if (YY_START==SkipVerbatim || YY_START == SkipCondVerbatim || YY_START==SkipCond || getLanguageFromFileName(yyextra->fileName)==SrcLangExt::Fortran || YY_START==IDLquote || YY_START == PragmaOnce)
2194 {
2195 REJECT;
2196 }
2197 else if (YY_START==RulesRoundDouble)
2198 {
2199 REJECT;
2200 }
2201 else
2202 {
2203 outputArray(yyscanner,yytext,yyleng);
2204 yyextra->lastCPPContext=YY_START;
2205 if (yyleng==3)
2206 {
2207 yyextra->isSpecialComment = true;
2208 yyextra->lastGuardName.clear(); // reset guard in case the #define is documented!
2209 }
2210 else
2211 {
2212 yyextra->isSpecialComment = false;
2213 }
2214 BEGIN(SkipCPPComment);
2215 }
2216 }
2217<*>\n {
2218 outputChar(yyscanner,'\n');
2219 yyextra->yyLineNr++;
2220 }
2221<*>. {
2222 yyextra->expectGuard = FALSE;
2223 outputChar(yyscanner,*yytext);
2224 }
2225
2226%%
2227
2228/////////////////////////////////////////////////////////////////////////////////////
2229
2230static int yyread(yyscan_t yyscanner,char *buf,int max_size)
2231{
2232 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2233 int bytesInBuf = static_cast<int>(state->inputBuf->size())-state->inputBufPos;
2234 int bytesToCopy = std::min(max_size,bytesInBuf);
2235 memcpy(buf,state->inputBuf->data()+state->inputBufPos,bytesToCopy);
2236 state->inputBufPos+=bytesToCopy;
2237 return bytesToCopy;
2238}
2239
2240static yy_size_t getFenceSize(char *txt, yy_size_t leng)
2241{
2242 yy_size_t fenceSize = 0;
2243 for (size_t i = 0; i < leng; i++)
2244 {
2245 if (txt[i] != ' ' && txt[i] != '*' && txt[i] != '\t') break;
2246 fenceSize++;
2247 }
2248 return leng-fenceSize;
2249}
2250
2251static void setFileName(yyscan_t yyscanner,const QCString &name)
2252{
2253 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2254 bool ambig = false;
2255 FileInfo fi(name.str());
2256 state->fileName=fi.absFilePath();
2257 state->yyFileDef=findFileDef(Doxygen::inputNameLinkedMap,state->fileName,ambig);
2258 if (state->yyFileDef==nullptr) // if this is not an input file check if it is an include file
2259 {
2260 state->yyFileDef=findFileDef(Doxygen::includeNameLinkedMap,state->fileName,ambig);
2261 }
2262 //printf("setFileName(%s) state->fileName=%s state->yyFileDef=%p\n",
2263 // name,qPrint(state->fileName),state->yyFileDef);
2264 if (state->yyFileDef && state->yyFileDef->isReference()) state->yyFileDef=nullptr;
2265 state->insideIDL = getLanguageFromFileName(state->fileName)==SrcLangExt::IDL;
2266 state->insideCS = getLanguageFromFileName(state->fileName)==SrcLangExt::CSharp;
2267 state->insideFtn = getLanguageFromFileName(state->fileName)==SrcLangExt::Fortran;
2268 EntryType section = guessSection(state->fileName);
2269 state->isSource = section.isHeader() || section.isSource();
2270}
2271
2272static void incrLevel(yyscan_t yyscanner)
2273{
2274 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2275 state->levelGuard.push(false);
2276 //printf("%s line %d: incrLevel %zu\n",qPrint(state->fileName),state->yyLineNr,state->levelGuard.size());
2277}
2278
2279static void decrLevel(yyscan_t yyscanner)
2280{
2281 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2282 //printf("%s line %d: decrLevel %zu\n",qPrint(state->fileName),state->yyLineNr,state->levelGuard.size());
2283 if (!state->levelGuard.empty())
2284 {
2285 state->levelGuard.pop();
2286 }
2287 else
2288 {
2289 if (state->condGuardErrorLine!=0)
2290 {
2291 warn(state->condGuardErrorFileName,state->condGuardErrorLine,"{}",state->condGuardErrorMessage);
2292 }
2293 else
2294 {
2295 warn(state->fileName,state->yyLineNr,"More #endif's than #if's found.");
2296 }
2297 }
2298}
2299
2300static bool otherCaseDone(yyscan_t yyscanner)
2301{
2302 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2303 if (state->levelGuard.empty())
2304 {
2305 warn(state->fileName,state->yyLineNr,"Found an #else without a preceding #if.");
2306 return TRUE;
2307 }
2308 else
2309 {
2310 return state->levelGuard.top();
2311 }
2312}
2313
2314static void setCaseDone(yyscan_t yyscanner,bool value)
2315{
2316 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2317 state->levelGuard.top()=value;
2318}
2319
2320
2321static std::unique_ptr<FileState> checkAndOpenFile(yyscan_t yyscanner,const QCString &fileName,bool &alreadyProcessed)
2322{
2323 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2324 alreadyProcessed = FALSE;
2325 std::unique_ptr<FileState> fs;
2326 //printf("checkAndOpenFile(%s)\n",qPrint(fileName));
2327 FileInfo fi(fileName.str());
2328 if (fi.exists() && fi.isFile())
2329 {
2330 const StringVector &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
2331 if (patternMatch(fi,exclPatterns)) return nullptr;
2332
2333 QCString absName = fi.absFilePath();
2334
2335 // global guard
2336 if (state->curlyCount==0) // not #include inside { ... }
2337 {
2338 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
2339 if (g_defineManager.alreadyProcessed(absName.str()))
2340 {
2341 alreadyProcessed = TRUE;
2342 //printf(" already included 1\n");
2343 return 0; // already done
2344 }
2345 }
2346 // check include stack for absName
2347
2348 alreadyProcessed = std::any_of(
2349 state->includeStack.begin(),
2350 state->includeStack.end(),
2351 [absName](const std::unique_ptr<FileState> &lfs)
2352 { return lfs->fileName==absName; }
2353 );
2354
2355 if (alreadyProcessed)
2356 {
2357 //printf(" already included 2\n");
2358 return nullptr;
2359 }
2360 //printf("#include %s\n",qPrint(absName));
2361
2362 fs = std::make_unique<FileState>();
2363 if (!readInputFile(absName,fs->fileBuf))
2364 { // error
2365 //printf(" error reading\n");
2366 fs.reset();
2367 }
2368 else
2369 {
2370 addTerminalCharIfMissing(fs->fileBuf,'\n');
2371 fs->oldFileBuf = state->inputBuf;
2372 fs->oldFileBufPos = state->inputBufPos;
2373 }
2374 }
2375 return fs;
2376}
2377
2378static std::unique_ptr<FileState> findFile(yyscan_t yyscanner, const QCString &fileName,bool localInclude,bool &alreadyProcessed)
2379{
2380 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2381 //printf("** findFile(%s,%d) state->fileName=%s\n",qPrint(fileName),localInclude,qPrint(state->fileName));
2382 if (Portable::isAbsolutePath(fileName))
2383 {
2384 auto fs = checkAndOpenFile(yyscanner,fileName,alreadyProcessed);
2385 if (fs)
2386 {
2387 setFileName(yyscanner,fileName);
2388 state->yyLineNr=1;
2389 return fs;
2390 }
2391 else if (alreadyProcessed)
2392 {
2393 return nullptr;
2394 }
2395 }
2396 if (localInclude && !state->fileName.isEmpty())
2397 {
2398 FileInfo fi(state->fileName.str());
2399 if (fi.exists())
2400 {
2401 QCString absName = QCString(fi.dirPath(TRUE))+"/"+fileName;
2402 auto fs = checkAndOpenFile(yyscanner,absName,alreadyProcessed);
2403 if (fs)
2404 {
2405 setFileName(yyscanner,absName);
2406 state->yyLineNr=1;
2407 return fs;
2408 }
2409 else if (alreadyProcessed)
2410 {
2411 return nullptr;
2412 }
2413 }
2414 }
2415 if (state->pathList.empty())
2416 {
2417 return nullptr;
2418 }
2419 for (auto path : state->pathList)
2420 {
2421 QCString absName = path+"/"+fileName;
2422 //printf(" Looking for %s in %s\n",fileName,qPrint(path));
2423 auto fs = checkAndOpenFile(yyscanner,absName,alreadyProcessed);
2424 if (fs)
2425 {
2426 setFileName(yyscanner,absName);
2427 state->yyLineNr=1;
2428 //printf(" -> found it\n");
2429 return fs;
2430 }
2431 else if (alreadyProcessed)
2432 {
2433 return nullptr;
2434 }
2435 }
2436 bool ambig = false;
2438 if (fd && !ambig) // fallback in case the file is uniquely named in the input, use that one
2439 {
2440 auto fs = checkAndOpenFile(yyscanner,fd->absFilePath(),alreadyProcessed);
2441 if (fs)
2442 {
2443 setFileName(yyscanner,fd->absFilePath());
2444 state->yyLineNr=1;
2445 //printf(" -> found it\n");
2446 return fs;
2447 }
2448 }
2449 return nullptr;
2450}
2451
2453{
2454 if (s.isEmpty()) return "";
2455 int i=(int)s.length()-1;
2456 while (i>=0)
2457 {
2458 char c=s[i];
2459 switch (c)
2460 {
2461 case '/':
2462 {
2463 i--;
2464 if (i>=0 && s[i]=='*') // end of a comment block
2465 {
2466 i--;
2467 while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--;
2468 if (i==0)
2469 {
2470 i++;
2471 }
2472 // only /*!< ... */ or /**< ... */ are treated as a comment for the macro name,
2473 // otherwise the comment is treated as part of the macro definition
2474 return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : "";
2475 }
2476 else
2477 {
2478 return "";
2479 }
2480 }
2481 break;
2482 // whitespace or line-continuation
2483 case ' ':
2484 case '\t':
2485 case '\r':
2486 case '\n':
2487 case '\\':
2488 break;
2489 default:
2490 return "";
2491 }
2492 i--;
2493 }
2494 return "";
2495}
2496
2497static int getNextChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint32_t &pos);
2498static int getCurrentChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint32_t pos);
2499static void unputChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint32_t &pos,char c);
2500static bool expandExpression(yyscan_t yyscanner,QCString &expr,QCString *rest,int pos,int level);
2501
2503{
2504 QCString result;
2505 uint32_t i=0;
2506 bool inString=FALSE;
2507 bool inChar=FALSE;
2508 char c,pc;
2509 while (i<s.length())
2510 {
2511 if (!inString && !inChar)
2512 {
2513 while (i<s.length() && !inString && !inChar)
2514 {
2515 c=s.at(i++);
2516 if (c=='"')
2517 {
2518 result+="\\\"";
2519 inString=TRUE;
2520 }
2521 else if (c=='\'')
2522 {
2523 result+=c;
2524 inChar=TRUE;
2525 }
2526 else
2527 {
2528 result+=c;
2529 }
2530 }
2531 }
2532 else if (inChar)
2533 {
2534 while (i<s.length() && inChar)
2535 {
2536 c=s.at(i++);
2537 if (c=='\'')
2538 {
2539 result+='\'';
2540 inChar=FALSE;
2541 }
2542 else if (c=='\\')
2543 {
2544 result+="\\\\";
2545 }
2546 else
2547 {
2548 result+=c;
2549 }
2550 }
2551 }
2552 else
2553 {
2554 pc=0;
2555 while (i<s.length() && inString)
2556 {
2557 c=s.at(i++);
2558 if (c=='"')
2559 {
2560 result+="\\\"";
2561 inString= pc=='\\';
2562 }
2563 else if (c=='\\')
2564 result+="\\\\";
2565 else
2566 result+=c;
2567 pc=c;
2568 }
2569 }
2570 }
2571 //printf("stringize '%s'->'%s'\n",qPrint(s),qPrint(result));
2572 return result;
2573}
2574
2575/*! Execute all ## operators in expr.
2576 * If the macro name before or after the operator contains a no-rescan
2577 * marker (@-) then this is removed (before the concatenated macro name
2578 * may be expanded again.
2579 */
2581{
2582 if (expr.isEmpty()) return;
2583 //printf("processConcatOperators: in='%s'\n",qPrint(expr));
2584 std::string e = expr.str();
2585 static const reg::Ex r(R"(\s*##\s*)");
2587
2588 size_t i=0;
2589 for (;;)
2590 {
2591 reg::Iterator it(e,r,i);
2592 if (it!=end)
2593 {
2594 const auto &match = *it;
2595 size_t n = match.position();
2596 size_t l = match.length();
2597 //printf("Match: '%s'\n",qPrint(expr.mid(i)));
2598 if (n+l+1<e.length() && e[static_cast<int>(n+l)]=='@' && expr[static_cast<int>(n+l+1)]=='-')
2599 {
2600 // remove no-rescan marker after ID
2601 l+=2;
2602 }
2603 //printf("found '%s'\n",qPrint(expr.mid(n,l)));
2604 // remove the ## operator and the surrounding whitespace
2605 e=e.substr(0,n)+e.substr(n+l);
2606 int k=static_cast<int>(n)-1;
2607 while (k>=0 && isId(e[k])) k--;
2608 if (k>0 && e[k]=='-' && e[k-1]=='@')
2609 {
2610 // remove no-rescan marker before ID
2611 e=e.substr(0,k-1)+e.substr(k+1);
2612 n-=2;
2613 }
2614 i=n;
2615 }
2616 else
2617 {
2618 break;
2619 }
2620 }
2621
2622 expr = e;
2623
2624 //printf("processConcatOperators: out='%s'\n",qPrint(expr));
2625}
2626
2627static void returnCharToStream(yyscan_t yyscanner,char c)
2628{
2629 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
2630 unput(c);
2631}
2632
2633static inline void addTillEndOfString(yyscan_t yyscanner,const QCString &expr,QCString *rest,
2634 uint32_t &pos,char term,QCString &arg)
2635{
2636 int cc;
2637 while ((cc=getNextChar(yyscanner,expr,rest,pos))!=EOF && cc!=0)
2638 {
2639 if (cc=='\\')
2640 {
2641 arg+=(char)cc;
2642 cc=getNextChar(yyscanner,expr,rest,pos);
2643 }
2644 else if (cc==term)
2645 {
2646 return;
2647 }
2648 arg+=(char)cc;
2649 }
2650}
2651
2652static void skipCommentMacroName(yyscan_t yyscanner, const QCString &expr, QCString *rest,
2653 int &cc, uint32_t &j, int &len)
2654{
2655 bool changed = false;
2656
2657 do
2658 {
2659 changed = false;
2660 while ((cc=getCurrentChar(yyscanner,expr,rest,j))!=EOF && cc!='\n' && isspace(cc))
2661 {
2662 len++;
2663 getNextChar(yyscanner,expr,rest,j);
2664 }
2665
2666 if (cc=='/') // possible start of a comment
2667 {
2668 int prevChar = '\0';
2669 getNextChar(yyscanner,expr,rest,j);
2670 if ((cc=getCurrentChar(yyscanner,expr,rest,j))!=EOF && cc == '*') // we have a comment
2671 {
2672 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2673 {
2674 if (cc == '/' && prevChar == '*') break; // we have an end of comment
2675 prevChar = cc;
2676 }
2677 if (cc != EOF) changed = true;
2678 }
2679 }
2680 } while (changed);
2681}
2682
2683// Expand C++20's __VA_OPT__(x) to either x if hasOptionalArgs==true or to the empty string if false
2684static QCString expandVAOpt(const QCString &vaStr,bool hasOptionalArgs)
2685{
2686 //printf("expandVAOpt(vaStr=%s,hasOptionalArgs=%d)\n",qPrint(vaStr),hasOptionalArgs);
2687 QCString result;
2688 int vo=0, vp=0;
2689 result.clear();
2690 int vl = static_cast<int>(vaStr.length());
2691 while ((vo = vaStr.find("__VA_OPT__(",vp))!=-1)
2692 {
2693 bool hasHash = vo>0 && vaStr.at(vo-1)=='#';
2694 if (hasHash)
2695 {
2696 result+=vaStr.mid(vp,vo-vp-1); // don't copy #
2697 result+="\"";
2698 }
2699 else
2700 {
2701 result+=vaStr.mid(vp,vo-vp);
2702 }
2703 int ve=vo+11; // skip over '__VA_OPT__(' part
2704 int bc=1;
2705 while (bc>0 && ve<vl)
2706 {
2707 if (vaStr[ve]==')') bc--;
2708 else if (vaStr[ve]=='(') bc++;
2709 ve++;
2710 }
2711 // ve points to end of __VA_OPT__(....)
2712 if (bc==0 && hasOptionalArgs)
2713 {
2714 QCString voStr = vaStr.mid(vo+11,ve-vo-12);
2715 //printf("vo=%d ve=%d voStr=%s\n",vo,ve,qPrint(voStr));
2716 result+=voStr; // take 'x' from __VA_OPT__(x)
2717 }
2718 if (hasHash)
2719 {
2720 result+="\"";
2721 }
2722 vp=ve;
2723 }
2724 result+=vaStr.mid(vp);
2725 //printf("vaStr='%s'\n -> '%s'\n",qPrint(vaStr),qPrint(result));
2726 return result;
2727}
2728
2729/*! replaces the function macro \a def whose argument list starts at
2730 * \a pos in expression \a expr.
2731 * Notice that this routine may scan beyond the \a expr string if needed.
2732 * In that case the characters will be read from the input file.
2733 * The replacement string will be returned in \a result and the
2734 * length of the (unexpanded) argument list is stored in \a len.
2735 */
2736static bool replaceFunctionMacro(yyscan_t yyscanner,const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result,int level)
2737{
2738 //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());
2739 uint32_t j=pos;
2740 len=0;
2741 result.clear();
2742 int cc;
2743
2744 skipCommentMacroName(yyscanner, expr, rest, cc, j, len);
2745
2746 if (cc!='(')
2747 {
2748 if (cc!=':') // don't add spaces for colons
2749 {
2750 unputChar(yyscanner,expr,rest,j,' ');
2751 }
2752 return FALSE;
2753 }
2754 getNextChar(yyscanner,expr,rest,j); // eat the '(' character
2755
2756 std::map<std::string,std::string> argTable; // list of arguments
2757 QCString arg;
2758 int argCount=0;
2759 int argCountNonEmpty=0;
2760 bool done=FALSE;
2761
2762 // PHASE 1: read the macro arguments
2763 if (def->nargs==0)
2764 {
2765 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2766 {
2767 char c = (char)cc;
2768 if (c==')') break;
2769 }
2770 }
2771 else
2772 {
2773 while (!done && (argCount<def->nargs || def->varArgs) &&
2774 ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2775 )
2776 {
2777 char c=(char)cc;
2778 if (c=='(') // argument is a function => search for matching )
2779 {
2780 int lvl=1;
2781 arg+=c;
2782 //char term='\0';
2783 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2784 {
2785 c=(char)cc;
2786 //printf("processing %c: term=%c (%d)\n",c,term,term);
2787 if (c=='\'' || c=='\"') // skip ('s and )'s inside strings
2788 {
2789 arg+=c;
2790 addTillEndOfString(yyscanner,expr,rest,j,c,arg);
2791 }
2792 if (c==')')
2793 {
2794 lvl--;
2795 arg+=c;
2796 if (lvl==0) break;
2797 }
2798 else if (c=='(')
2799 {
2800 lvl++;
2801 arg+=c;
2802 }
2803 else
2804 {
2805 arg+=c;
2806 }
2807 }
2808 }
2809 else if (c==')' || c==',') // last or next argument found
2810 {
2811 if (c==',' && argCount==def->nargs-1 && def->varArgs)
2812 {
2813 expandExpression(yyscanner,arg,nullptr,0,level+1);
2814 arg=arg.stripWhiteSpace();
2815 arg+=',';
2816 }
2817 else
2818 {
2819 expandExpression(yyscanner,arg,nullptr,0,level+1);
2820 arg=arg.stripWhiteSpace();
2821 QCString argKey;
2822 argKey.sprintf("@%d",argCount++); // key name
2823 if (c==',' || !arg.isEmpty()) argCountNonEmpty++;
2824 // add argument to the lookup table
2825 argTable.emplace(toStdString(argKey), toStdString(arg));
2826 arg.clear();
2827 if (c==')') // end of the argument list
2828 {
2829 done=TRUE;
2830 }
2831 }
2832 }
2833 else if (c=='\"') // append literal strings
2834 {
2835 arg+=c;
2836 bool found=FALSE;
2837 while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2838 {
2839 found = cc=='"';
2840 if (cc=='\\')
2841 {
2842 c=(char)cc;
2843 arg+=c;
2844 if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break;
2845 }
2846 c=(char)cc;
2847 arg+=c;
2848 }
2849 }
2850 else if (c=='\'') // append literal characters
2851 {
2852 arg+=c;
2853 bool found=FALSE;
2854 while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2855 {
2856 found = cc=='\'';
2857 if (cc=='\\')
2858 {
2859 c=(char)cc;
2860 arg+=c;
2861 if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break;
2862 }
2863 c=(char)cc;
2864 arg+=c;
2865 }
2866 }
2867 else if (c=='/') // possible start of a comment
2868 {
2869 char prevChar = '\0';
2870 arg+=c;
2871 if ((cc=getCurrentChar(yyscanner,expr,rest,j)) == '*') // we have a comment
2872 {
2873 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2874 {
2875 c=(char)cc;
2876 arg+=c;
2877 if (c == '/' && prevChar == '*') break; // we have an end of comment
2878 prevChar = c;
2879 }
2880 }
2881 }
2882 else // append other characters
2883 {
2884 arg+=c;
2885 }
2886 }
2887 }
2888
2889 // PHASE 2: apply the macro function
2890 if (argCount==def->nargs || // same number of arguments
2891 (argCount>=def->nargs-1 && def->varArgs)) // variadic macro with at least as many
2892 // params as the non-variadic part (see bug731985)
2893 {
2894 uint32_t k=0;
2895 // substitution of all formal arguments
2896 QCString resExpr;
2898 //printf("varArgs=%d argCount=%d def->nargs=%d d=%s\n",def->varArgs,argCount,def->nargs,qPrint(d));
2899 if (def->varArgs) d = expandVAOpt(d,argCountNonEmpty!=def->nargs-1);
2900 //printf("Macro definition: '%s'\n",qPrint(d));
2901 bool inString=FALSE;
2902 while (k<d.length())
2903 {
2904 if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
2905 {
2906 if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
2907 {
2908 k+=2;
2909 resExpr+="@@"; // we unescape these later
2910 }
2911 else if (d.at(k+1)=='-') // no-rescan marker
2912 {
2913 k+=2;
2914 resExpr+="@-";
2915 }
2916 else // argument marker => read the argument number
2917 {
2918 QCString key="@";
2919 bool hash=FALSE;
2920 int l=k-1;
2921 // search for ## backward
2922 if (l>=0 && d.at(l)=='"') l--;
2923 while (l>=0 && d.at(l)==' ') l--;
2924 if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
2925 k++;
2926 // scan the number
2927 while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
2928 if (!hash)
2929 {
2930 // search for ## forward
2931 l=k;
2932 if (l<(int)d.length() && d.at(l)=='"') l++;
2933 while (l<(int)d.length() && d.at(l)==' ') l++;
2934 if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
2935 }
2936 //printf("request key %s result %s\n",qPrint(key),argTable[key]->data());
2937 auto it = argTable.find(key.str());
2938 if (it!=argTable.end())
2939 {
2940 QCString substArg = it->second;
2941 //printf("substArg='%s'\n",qPrint(substArg));
2942 // only if no ## operator is before or after the argument
2943 // marker we do macro expansion.
2944 if (!hash)
2945 {
2946 expandExpression(yyscanner,substArg,nullptr,0,level+1);
2947 }
2948 if (inString)
2949 {
2950 //printf("'%s'=stringize('%s')\n",qPrint(stringize(*subst)),subst->data());
2951
2952 // if the marker is inside a string (because a # was put
2953 // before the macro name) we must escape " and \ characters
2954 resExpr+=stringize(substArg);
2955 }
2956 else
2957 {
2958 if (hash && substArg.isEmpty())
2959 {
2960 resExpr+="@E"; // empty argument will be remove later on
2961 }
2962 resExpr+=substArg;
2963 }
2964 }
2965 }
2966 }
2967 else // no marker, just copy
2968 {
2969 if (!inString && d.at(k)=='\"')
2970 {
2971 inString=TRUE; // entering a literal string
2972 }
2973 else if (k>2 && inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
2974 {
2975 inString=FALSE; // leaving a literal string
2976 }
2977 resExpr+=d.at(k++);
2978 }
2979 }
2980 len=j-pos;
2981 result=resExpr;
2982 //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());
2983 return TRUE;
2984 }
2985 //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());
2986 return FALSE;
2987}
2988
2989
2990/*! returns the next identifier in string \a expr by starting at position \a p.
2991 * The position of the identifier is returned (or -1 if nothing is found)
2992 * and \a l is its length. Any quoted strings are skipping during the search.
2993 */
2994static int getNextId(const QCString &expr,int p,int *l)
2995{
2996 int n;
2997 while (p<(int)expr.length())
2998 {
2999 char c=expr.at(p++);
3000 if (isdigit(c)) // skip number
3001 {
3002 while (p<(int)expr.length() && isId(expr.at(p))) p++;
3003 }
3004 else if (isalpha(c) || c=='_') // read id
3005 {
3006 n=p-1;
3007 while (p<(int)expr.length() && isId(expr.at(p))) p++;
3008 *l=p-n;
3009 return n;
3010 }
3011 else if (c=='"') // skip string
3012 {
3013 char ppc=0,pc=c;
3014 if (p<(int)expr.length()) c=expr.at(p);
3015 while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\')))
3016 // continue as long as no " is found, but ignoring \", but not \\"
3017 {
3018 ppc=pc;
3019 pc=c;
3020 c=expr.at(p);
3021 p++;
3022 }
3023 if (p<(int)expr.length()) ++p; // skip closing quote
3024 }
3025 else if (c=='/') // skip C Comment
3026 {
3027 //printf("Found C comment at p=%d\n",p);
3028 char pc=c;
3029 if (p<(int)expr.length())
3030 {
3031 c=expr.at(p);
3032 if (c=='*') // Start of C comment
3033 {
3034 p++;
3035 while (p<(int)expr.length() && !(pc=='*' && c=='/'))
3036 {
3037 pc=c;
3038 c=expr.at(p++);
3039 }
3040 }
3041 }
3042 //printf("Found end of C comment at p=%d\n",p);
3043 }
3044 }
3045 return -1;
3046}
3047
3048#define MAX_EXPANSION_DEPTH 50
3049
3050static void addSeparatorsIfNeeded(yyscan_t yyscanner,const QCString &expr,QCString &resultExpr,QCString &restExpr,int pos)
3051{
3052 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3053 if (!state->nospaces)
3054 {
3055 // peek back in the stream, for a colon character
3056 char ccPrev = pos==0 || (int)expr.length()<pos ? state->prevChar : expr.at(pos-1);
3057 QCString leftSpace = ccPrev!=':' && ccPrev!=' ' ? " " : "";
3058 int ccNext = 0;
3059 restExpr=restExpr.stripWhiteSpace();
3060 if (restExpr.isEmpty()) // peek ahead in the stream for non-whitespace
3061 {
3062 uint32_t j=(uint32_t)resultExpr.length();
3063 while ((ccNext=getNextChar(yyscanner,resultExpr,nullptr,j))!=EOF && ccNext==' ') { }
3064 if (ccNext != EOF) unputChar(yyscanner,resultExpr,nullptr,j,(char)ccNext);
3065 }
3066 else // take first char from remainder
3067 {
3068 ccNext=restExpr.at(0);
3069 }
3070 // don't add whitespace before a colon
3071 QCString rightSpace = ccNext!=':' && ccNext!=' ' ? " " : "";
3072 //printf("ccPrev='%c' ccNext='%c' p=%d expr=%zu restExpr='%s' left='%s' right='%s'\n",
3073 // ccPrev,ccNext,pos,expr.length(),qPrint(restExpr),qPrint(leftSpace),qPrint(rightSpace));
3074 resultExpr=leftSpace+resultExpr+rightSpace;
3075 }
3076}
3077
3078/*! performs recursive macro expansion on the string \a expr
3079 * starting at position \a pos.
3080 * May read additional characters from the input while re-scanning!
3081 */
3082static bool expandExpression(yyscan_t yyscanner,QCString &expr,QCString *rest,int pos,int level)
3083{
3084 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3085 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3086 //printf(">expandExpression(expr='%s',rest='%s',pos=%d,level=%d)\n",qPrint(expr),rest ? qPrint(*rest) : "", pos, level);
3087 if (expr.isEmpty())
3088 {
3089 //printf("<expandExpression: empty\n");
3090 return TRUE;
3091 }
3092 if (state->expanded.find(expr.str())!=state->expanded.end() &&
3093 level>MAX_EXPANSION_DEPTH) // check for too deep recursive expansions
3094 {
3095 //printf("<expandExpression: already expanded expr='%s'\n",qPrint(expr));
3096 return FALSE;
3097 }
3098 else
3099 {
3100 state->expanded.insert(expr.str());
3101 }
3102 QCString macroName;
3103 QCString expMacro;
3104 bool definedTest=FALSE;
3105 int i=pos, l=0, p=0, len=0;
3106 int startPos = pos;
3107 int samePosCount=0;
3108 while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
3109 {
3110 bool replaced=FALSE;
3111 QCString resultExpr;
3112 macroName=expr.mid(p,l);
3113 //printf(" p=%d macroName=%s\n",p,qPrint(macroName));
3114 if (!(resultExpr = expandStandardMacro(yyscanner,macroName)).isEmpty())
3115 {
3116 QCString restExpr=expr.right(expr.length()-8-p);
3117 expr=expr.left(p)+resultExpr+restExpr;
3118 }
3119 else if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
3120 {
3121 if (state->expandedDict.find(macroName.str())==state->expandedDict.end()) // expand macro
3122 {
3123 bool expanded=false;
3124 Define *def=isDefined(yyscanner,macroName);
3125 // In case EXPAND_ONLY_PREDEF is enabled prevent expansion unless the macro was explicitly
3126 // predefined
3127 if (yyextra->expandOnlyPredef && def && !def->isPredefined) def=nullptr;
3128 if (macroName=="defined")
3129 {
3130 //printf("found defined inside macro definition '%s'\n",qPrint(expr.right(expr.length()-p)));
3131 definedTest=TRUE;
3132 }
3133 else if (definedTest) // macro name was found after defined
3134 {
3135 if (def) expMacro = " 1 "; else expMacro = " 0 ";
3136 replaced=TRUE;
3137 len=l;
3138 definedTest=FALSE;
3139 }
3140 else if (def && def->nargs==-1) // simple macro
3141 {
3142 // substitute the definition of the macro
3143 expMacro=def->definition.stripWhiteSpace();
3144 //expMacro=def->definition.stripWhiteSpace();
3145 replaced=TRUE;
3146 len=l;
3147 //printf("simple macro expansion='%s'->'%s'\n",qPrint(macroName),qPrint(expMacro));
3148 }
3149 else if (def && def->nargs>=0) // function macro
3150 {
3151 //printf(" >>>> call replaceFunctionMacro expr='%s'\n",qPrint(expr));
3152 replaced=replaceFunctionMacro(yyscanner,expr,rest,p+l,len,def,expMacro,level);
3153 //printf(" <<<< call replaceFunctionMacro: replaced=%d\n",replaced);
3154 len+=l;
3155 }
3156
3157 if (replaced) // expand the macro and rescan the expression
3158 {
3159 //printf(" replacing '%s'->'%s'\n",qPrint(expr.mid(p,len)),qPrint(expMacro));
3160 resultExpr=expMacro;
3161 QCString restExpr=expr.right(expr.length()-len-p);
3162 addSeparatorsIfNeeded(yyscanner,expr,resultExpr,restExpr,p);
3163 processConcatOperators(resultExpr);
3164 //printf(" macroName=%s restExpr='%s' def->nonRecursive=%d\n",qPrint(macroName),qPrint(restExpr),def ? def->nonRecursive : false);
3165 if (def && !def->nonRecursive)
3166 {
3167 state->expandedDict.emplace(toStdString(macroName),def);
3168 expanded = expandExpression(yyscanner,resultExpr,&restExpr,0,level+1);
3169 state->expandedDict.erase(toStdString(macroName));
3170 }
3171 else if (def && def->nonRecursive)
3172 {
3173 expanded = true;
3174 }
3175 if (expanded)
3176 {
3177 //printf("expanded '%s' + '%s' + '%s'\n",qPrint(expr.left(p)),qPrint(resultExpr),qPrint(restExpr));
3178 expr=expr.left(p)+resultExpr+restExpr;
3179 i=p;
3180 }
3181 else
3182 {
3183 //printf("not expanded '%s' + @- '%s'\n",qPrint(expr.left(p)),qPrint(expr.right(expr.length()-p)));
3184 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
3185 i=p+l+2;
3186 }
3187 }
3188 else // move to the next macro name
3189 {
3190 //printf(" moving to the next macro old i=%d new i=%d\n",i,p+l);
3191 i=p+l;
3192 }
3193 }
3194 else // move to the next macro name
3195 {
3196 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
3197 //printf("macro already expanded, moving to the next macro expr=%s\n",qPrint(expr));
3198 i=p+l+2;
3199 //i=p+l;
3200 }
3201 // check for too many inplace expansions without making progress
3202 if (i==startPos)
3203 {
3204 samePosCount++;
3205 }
3206 else
3207 {
3208 startPos=i;
3209 samePosCount=0;
3210 }
3211 if (samePosCount>MAX_EXPANSION_DEPTH)
3212 {
3213 break;
3214 }
3215 }
3216 else // no re-scan marker found, skip the macro name
3217 {
3218 //printf("skipping marked macro\n");
3219 i=p+l;
3220 }
3221 }
3222 //printf("<expandExpression(expr='%s',rest='%s',pos=%d,level=%d)\n",qPrint(expr),rest ? qPrint(*rest) : "", pos,level);
3223 return TRUE;
3224}
3225
3226/*! @brief Process string or character literal.
3227 *
3228 * \a inputStr should point to the start of a string or character literal.
3229 * the routine will return a pointer to just after the end of the literal
3230 * the character making up the literal will be added to \a result.
3231 */
3232static const char *processUntilMatchingTerminator(const char *inputStr,QCString &result)
3233{
3234 if (inputStr==nullptr) return inputStr;
3235 char term = *inputStr; // capture start character of the literal
3236 if (term!='\'' && term!='"') return inputStr; // not a valid literal
3237 char c=term;
3238 // output start character
3239 result+=c;
3240 inputStr++;
3241 while ((c=*inputStr)) // while inside the literal
3242 {
3243 if (c==term) // found end marker of the literal
3244 {
3245 // output end character and stop
3246 result+=c;
3247 inputStr++;
3248 break;
3249 }
3250 else if (c=='\\') // escaped character, process next character
3251 // as well without checking for end marker.
3252 {
3253 result+=c;
3254 inputStr++;
3255 c=*inputStr;
3256 if (c==0) break; // unexpected end of string after escape character
3257 }
3258 result+=c;
3259 inputStr++;
3260 }
3261 return inputStr;
3262}
3263
3264/*! replaces all occurrences of @@@@ in \a s by @@
3265 * and removes all occurrences of @@E.
3266 * All identifiers found are replaced by 0L
3267 */
3269{
3270 static const std::vector<std::string> signs = { "signed", "unsigned" };
3271 struct TypeInfo { std::string name; size_t size; };
3272 static const std::vector<TypeInfo> types = {
3273 { "short int", sizeof(short int) },
3274 { "long long int", sizeof(long long int) },
3275 { "long int", sizeof(long int) },
3276 { "long long", sizeof(long long) },
3277 { "long double", sizeof(long double) },
3278 { "int", sizeof(int) },
3279 { "short", sizeof(short) },
3280 { "bool", sizeof(bool) },
3281 { "long", sizeof(long) },
3282 { "char", sizeof(char) },
3283 { "float", sizeof(float) },
3284 { "double", sizeof(double) },
3285 };
3286
3287 // Check if string p starts with basic types ending with a ')', such as 'signed long)' or ' float )'
3288 // and return the pointer just past the ')' and the size of the type as a tuple.
3289 // If the pattern is not found the tuple (nullptr,0) is returned.
3290 auto process_cast_or_sizeof = [](const char *p) -> std::pair<const char *,size_t>
3291 {
3292 const char *q = p;
3293 while (*q==' ' || *q=='\t') q++;
3294 bool found=false;
3295 size_t size = sizeof(int); // '(signed)' or '(unsigned)' is an int type
3296 for (const auto &sgn : signs)
3297 {
3298 if (qstrncmp(q,sgn.c_str(),sgn.length())==0) { q+=sgn.length(); found=true; }
3299 }
3300 if (!found || *q==' ' || *q=='\t' || *q==')') // continue searching
3301 {
3302 while (*q==' ' || *q=='\t') q++;
3303 for (const auto &t : types)
3304 {
3305 if (qstrncmp(q,t.name.c_str(),t.name.length())==0)
3306 {
3307 q += t.name.length();
3308 size = t.size;
3309 break;
3310 }
3311 }
3312 while (*q==' ' || *q=='\t') q++;
3313 if (*q==')') return std::make_pair(++q,size);
3314 }
3315 return std::make_pair(nullptr,0);
3316 };
3317
3318 //printf("removeIdsAndMarkers(%s)\n",qPrint(s));
3319 if (s.isEmpty()) return s;
3320 const char *p=s.data();
3321 bool inNum=FALSE;
3322 QCString result;
3323 if (p)
3324 {
3325 char c = 0;
3326 while ((c=*p))
3327 {
3328 if (c=='(') // potential cast, ignore it
3329 {
3330 const char *q = process_cast_or_sizeof(p+1).first;
3331 //printf("potential cast:\nin: %s\nout: %s\n",p,q);
3332 if (q)
3333 {
3334 p=q;
3335 continue;
3336 }
3337 }
3338 else if (c=='s' && literal_at(p,"sizeof")) // sizeof(...)
3339 {
3340 const char *q = p+6;
3341 while (*q==' ' || *q=='\t') q++;
3342 if (*q=='(')
3343 {
3344 auto r = process_cast_or_sizeof(q+1);
3345 //printf("sizeof:\nin: %s\nout: %zu%s\n--> sizeof=%zu\n",p,r.second,r.first,r.second);
3346 if (r.first)
3347 {
3348 result+=QCString().setNum(r.second);
3349 p=r.first;
3350 continue;
3351 }
3352 }
3353 }
3354
3355 if (c=='@') // replace @@ with @ and remove @E
3356 {
3357 if (*(p+1)=='@')
3358 {
3359 result+=c;
3360 }
3361 else if (*(p+1)=='E')
3362 {
3363 // skip
3364 }
3365 p+=2;
3366 }
3367 else if (isdigit(c)) // number
3368 {
3369 result+=c;
3370 p++;
3371 inNum=TRUE;
3372 }
3373 else if (c=='\'') // quoted character
3374 {
3375 p = processUntilMatchingTerminator(p,result);
3376 }
3377 else if (c=='d' && !inNum) // identifier starting with a 'd'
3378 {
3379 if (literal_at(p,"defined ") || literal_at(p,"defined("))
3380 // defined keyword
3381 {
3382 p+=7; // skip defined
3383 }
3384 else
3385 {
3386 result+="0L";
3387 p++;
3388 while ((c=*p) && isId(c)) p++;
3389 }
3390 }
3391 else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
3392 {
3393 result+="0L";
3394 p++;
3395 while ((c=*p) && isId(c)) p++;
3396 while ((c=*p) && isspace((uint8_t)c)) p++;
3397 if (*p=='(') // undefined function macro
3398 {
3399 p++;
3400 int count=1;
3401 while ((c=*p++))
3402 {
3403 if (c=='(') count++;
3404 else if (c==')')
3405 {
3406 count--;
3407 if (count==0) break;
3408 }
3409 else if (c=='/')
3410 {
3411 char pc=c;
3412 c=*++p;
3413 if (c=='*') // start of C comment
3414 {
3415 while (*p && !(pc=='*' && c=='/')) // search end of comment
3416 {
3417 pc=c;
3418 c=*++p;
3419 }
3420 p++;
3421 }
3422 }
3423 }
3424 }
3425 }
3426 else if (c=='/') // skip C comments
3427 {
3428 char pc=c;
3429 c=*++p;
3430 if (c=='*') // start of C comment
3431 {
3432 while (*p && !(pc=='*' && c=='/')) // search end of comment
3433 {
3434 pc=c;
3435 c=*++p;
3436 }
3437 p++;
3438 }
3439 else // oops, not comment but division
3440 {
3441 result+=pc;
3442 goto nextChar;
3443 }
3444 }
3445 else
3446 {
3447nextChar:
3448 result+=c;
3449 char lc=(char)tolower(c);
3450 if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE;
3451 p++;
3452 }
3453 }
3454 }
3455 //printf("removeIdsAndMarkers(%s)=%s\n",s,qPrint(result));
3456 return result;
3457}
3458
3459/*! replaces all occurrences of @@ in \a s by @
3460 * \par assumption:
3461 * \a s only contains pairs of @@'s
3462 */
3464{
3465 if (s.isEmpty()) return s;
3466 const char *p=s.data();
3467 QCString result;
3468 if (p)
3469 {
3470 char c = 0;
3471 while ((c=*p))
3472 {
3473 switch(c)
3474 {
3475 case '@': // replace @@ with @
3476 {
3477 if (*(p+1)=='@')
3478 {
3479 result+=c;
3480 }
3481 p+=2;
3482 }
3483 break;
3484 case '/': // skip C comments
3485 {
3486 result+=c;
3487 char pc=c;
3488 c=*++p;
3489 if (c=='*') // start of C comment
3490 {
3491 while (*p && !(pc=='*' && c=='/')) // search end of comment
3492 {
3493 if (*p=='@' && *(p+1)=='@')
3494 {
3495 result+=c;
3496 p++;
3497 }
3498 else
3499 {
3500 result+=c;
3501 }
3502 pc=c;
3503 c=*++p;
3504 }
3505 if (*p)
3506 {
3507 result+=c;
3508 p++;
3509 }
3510 }
3511 }
3512 break;
3513 case '"': // skip string literals
3514 case '\'': // skip char literals
3515 p = processUntilMatchingTerminator(p,result);
3516 break;
3517 default:
3518 {
3519 result+=c;
3520 p++;
3521 }
3522 break;
3523 }
3524 }
3525 }
3526 //printf("RemoveMarkers(%s)=%s\n",s,qPrint(result));
3527 return result;
3528}
3529
3530/*! compute the value of the expression in string \a expr.
3531 * If needed the function may read additional characters from the input.
3532 */
3533
3534static bool computeExpression(yyscan_t yyscanner,const QCString &expr)
3535{
3536 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3537 QCString e=expr;
3538 QCString ee=expr;
3539 ee = removeMarkers(ee);
3540 state->expanded.clear();
3541 expandExpression(yyscanner,e,nullptr,0,0);
3542 //printf("after expansion '%s'\n",qPrint(e));
3543 e = removeIdsAndMarkers(e);
3544 if (e.isEmpty()) return FALSE;
3545 //printf("parsing '%s'\n",qPrint(e));
3546 return state->constExpParser.parse(state->fileName.data(),state->yyLineNr,e.str(),ee.str());
3547}
3548
3549/*! expands the macro definition in \a name
3550 * If needed the function may read additional characters from the input
3551 */
3552
3553static QCString expandMacro(yyscan_t yyscanner,const QCString &name)
3554{
3555 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3556 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3557 state->prevChar = yyscanner->yytext_r > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ? *(yyscanner->yytext_r-1) : 0;
3558 QCString n=name;
3559 state->expanded.clear();
3560 expandExpression(yyscanner,n,nullptr,0,0);
3561 n=removeMarkers(n);
3562 state->prevChar=0;
3563 //printf("expandMacro '%s'->'%s'\n",qPrint(name),qPrint(n));
3564 return n;
3565}
3566
3567static QCString expandStandardMacro(yyscan_t yyscanner,const QCString &name)
3568{
3569 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3570 QCString resultExpr;
3571 if (name == "__LINE__")
3572 {
3573 return QCString().setNum(yyextra->yyLineNr);
3574 }
3575 else if (name == "__FILE__")
3576 {
3577 resultExpr = "\"";
3578 resultExpr += yyextra->fileName;
3579 resultExpr += "\"";
3580 }
3581 else if (name == "__DATE__")
3582 {
3583 resultExpr = "\"";
3584 resultExpr += __DATE__;
3585 resultExpr += "\"";
3586 }
3587 else if (name == "__TIME__")
3588 {
3589 resultExpr = "\"";
3590 resultExpr += __TIME__;
3591 resultExpr += "\"";
3592 }
3593 return resultExpr;
3594}
3595
3596static void addDefine(yyscan_t yyscanner)
3597{
3598 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3599 Define def;
3600 def.name = state->defName;
3601 def.definition = state->defText.stripWhiteSpace();
3602 def.nargs = state->defArgs;
3603 def.fileName = state->fileName;
3604 def.fileDef = state->yyFileDef;
3605 def.lineNr = state->yyLineNr-state->yyMLines;
3606 def.columnNr = state->yyColNr;
3607 def.varArgs = state->defVarArgs;
3608 //printf("newDefine: %s %s file: %s\n",qPrint(def.name),qPrint(def.definition),
3609 // def.fileDef ? qPrint(def.fileDef->name()) : qPrint(def.fileName));
3610 //printf("newDefine: '%s'->'%s'\n",qPrint(def.name),qPrint(def.definition));
3611 if (!def.name.isEmpty() &&
3613 {
3614 def.isPredefined=TRUE;
3616 }
3617 auto it = state->localDefines.find(def.name.str());
3618 if (it!=state->localDefines.end()) // redefine
3619 {
3620 state->localDefines.erase(it);
3621 }
3622 state->localDefines.emplace(def.name.str(),def);
3623}
3624
3625static void addMacroDefinition(yyscan_t yyscanner)
3626{
3627 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3628 if (state->skip) return; // do not add this define as it is inside a
3629 // conditional section (cond command) that is disabled.
3630
3631 Define define;
3632 define.fileName = state->fileName;
3633 define.lineNr = state->yyLineNr - state->yyMLines;
3634 define.columnNr = state->yyColNr;
3635 define.name = state->defName;
3636 define.args = state->defArgsStr;
3637 define.fileDef = state->inputFileDef;
3638
3639 QCString litText = state->defLitText;
3640 int l=litText.find('\n');
3641 if (l>0 && litText.left(l).stripWhiteSpace()=="\\")
3642 {
3643 // strip first line if it only contains a slash
3644 litText = litText.right(litText.length()-l-1);
3645 }
3646 else if (l>0)
3647 {
3648 // align the items on the first line with the items on the second line
3649 int k=l+1;
3650 const char *p=litText.data()+k;
3651 char c = 0;
3652 while ((c=*p++) && (c==' ' || c=='\t')) k++;
3653 litText=litText.mid(l+1,k-l-1)+litText.stripWhiteSpace();
3654 }
3655 QCString litTextStripped = state->defLitText.stripWhiteSpace();
3656 if (litTextStripped.contains('\n')>=1)
3657 {
3658 define.definition = litText;
3659 }
3660 else
3661 {
3662 define.definition = litTextStripped;
3663 }
3664 {
3665 state->macroDefinitions.push_back(define);
3666 }
3667}
3668
3669static inline void outputChar(yyscan_t yyscanner,char c)
3670{
3671 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3672 if (state->includeStack.empty() || state->curlyCount>0) (*state->outputBuf)+=c;
3673}
3674
3675static inline void outputArray(yyscan_t yyscanner,const char *a,yy_size_t len)
3676{
3677 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3678 if (state->includeStack.empty() || state->curlyCount>0) (*state->outputBuf)+=std::string_view(a,len);
3679}
3680
3681static inline void outputString(yyscan_t yyscanner,const QCString &a)
3682{
3683 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3684 if (state->includeStack.empty() || state->curlyCount>0) (*state->outputBuf)+=a.str();
3685}
3686
3687static inline void outputSpace(yyscan_t yyscanner,char c)
3688{
3689 if (c=='\t') outputChar(yyscanner,'\t');
3690 else outputChar(yyscanner,' ');
3691}
3692
3693static inline void outputSpaces(yyscan_t yyscanner,char *s)
3694{
3695 const char *p=s;
3696 char c = 0;
3697 while ((c=*p++))
3698 {
3699 if (c=='\t') outputChar(yyscanner,'\t');
3700 else outputChar(yyscanner,' ');
3701 }
3702}
3703
3704static inline void extraSpacing(yyscan_t yyscanner)
3705{
3706 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3707 if (!yyextra->defContinue) return;
3708 for (int i=0; i< (int)yyleng; i++)
3709 {
3710 if (yytext[i] == '\t')
3711 yyextra->defExtraSpacing+='\t';
3712 else
3713 yyextra->defExtraSpacing+=' ';
3714 }
3715}
3716
3717static void determineBlockName(yyscan_t yyscanner)
3718{
3719 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3720 yyextra->fenceSize=0;
3721 char c=0;
3722 if (yytext[1]=='f' && ((c=yytext[2])=='[' || c=='{' || c=='(' || c=='$'))
3723 {
3724 switch (c)
3725 {
3726 case '[': yyextra->blockName="]"; break;
3727 case '{': yyextra->blockName="}"; break;
3728 case '(': yyextra->blockName=")"; break;
3729 case '$': yyextra->blockName="$"; break;
3730 default: break;
3731 }
3732 yyextra->blockName=yyextra->blockName.stripWhiteSpace();
3733 }
3734 else
3735 {
3736 QCString bn=QCString(&yytext[1]).stripWhiteSpace();
3737 if (bn=="startuml")
3738 {
3739 yyextra->blockName="uml";
3740 }
3741 else
3742 {
3743 int i = bn.find('{'); // for \code{.c}
3744 if (i!=-1) bn=bn.left(i).stripWhiteSpace();
3745 yyextra->blockName=bn;
3746 }
3747 }
3748}
3749
3750static void readIncludeFile(yyscan_t yyscanner,const QCString &inc)
3751{
3752 AUTO_TRACE("inc={}",inc);
3753 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3754 uint32_t i=0;
3755
3756 // find the start of the include file name
3757 while (i<inc.length() &&
3758 (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
3759 ) i++;
3760 uint32_t s=i;
3761
3762 // was it a local include?
3763 bool localInclude = s>0 && inc.at(s-1)=='"';
3764
3765 // find the end of the include file name
3766 while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
3767
3768 if (s<inc.length() && i>s) // valid include file name found
3769 {
3770 // extract include path+name
3771 QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
3772 if (incFileName.endsWith(".exe") || incFileName.endsWith(".dll") || incFileName.endsWith(".tlb"))
3773 {
3774 // skip imported binary files (e.g. M$ type libraries)
3775 return;
3776 }
3777
3778 QCString oldFileName = state->fileName;
3779 FileDef *oldFileDef = state->yyFileDef;
3780 int oldLineNr = state->yyLineNr;
3781 //printf("Searching for '%s'\n",qPrint(incFileName));
3782
3783 QCString absIncFileName = determineAbsoluteIncludeName(state->fileName,incFileName);
3784
3785 // findFile will overwrite state->yyFileDef if found
3786 std::unique_ptr<FileState> fs;
3787 bool alreadyProcessed = FALSE;
3788 //printf("calling findFile(%s)\n",qPrint(incFileName));
3789 fs=findFile(yyscanner,absIncFileName,localInclude,alreadyProcessed); // see if the absolute include file can be found
3790 if (fs)
3791 {
3792 {
3793 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
3794 g_defineManager.addInclude(oldFileName.str(),absIncFileName.str());
3795 }
3796
3797 //printf("Found include file!\n");
3799 {
3800 for (i=0;i<state->includeStack.size();i++)
3801 {
3803 }
3804 Debug::print(Debug::Preprocessor,0,"#include {}: parsing...\n",incFileName);
3805 }
3806
3807 if (state->includeStack.empty() && oldFileDef)
3808 {
3809 PreIncludeInfo *ii = state->includeRelations.find(absIncFileName);
3810 if (ii==nullptr)
3811 {
3812 bool ambig = false;
3813 FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
3814 state->includeRelations.add(
3815 absIncFileName,
3816 oldFileDef,
3817 ambig ? nullptr : incFd,
3818 incFileName,
3819 localInclude,
3820 state->isImported
3821 );
3822 }
3823 }
3824
3825 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3826 fs->bufState = YY_CURRENT_BUFFER;
3827 fs->lineNr = oldLineNr;
3828 fs->fileName = oldFileName;
3829 fs->curlyCount = state->curlyCount;
3830 //state->curlyCount = 0; // don't reset counter, see issue #10997
3831 fs->lexRulesPart = state->lexRulesPart;
3832 fs->levelGuard = state->levelGuard;
3833 while (!state->levelGuard.empty()) state->levelGuard.pop();
3834 state->lexRulesPart = false;
3835 // push the state on the stack
3836 FileState *fs_ptr = fs.get();
3837 state->includeStack.push_back(std::move(fs));
3838 // set the scanner to the include file
3839
3840 // Deal with file changes due to
3841 // #include's within { .. } blocks
3842 QCString lineStr(state->fileName.length()+20, QCString::ExplicitSize);
3843 lineStr.sprintf("# 1 \"%s\" 1\n",qPrint(state->fileName));
3844 outputString(yyscanner,lineStr);
3845
3846 AUTO_TRACE_ADD("Switching to include file {}",incFileName);
3847 state->expectGuard=TRUE;
3848 state->inputBuf = &fs_ptr->fileBuf;
3849 state->inputBufPos=0;
3850 yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE, yyscanner),yyscanner);
3851 }
3852 else
3853 {
3854 if (alreadyProcessed) // if this header was already process we can just copy the stored macros
3855 // in the local context
3856 {
3857 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
3858 g_defineManager.addInclude(state->fileName.str(),absIncFileName.str());
3859 g_defineManager.retrieve(absIncFileName.str(),state->contextDefines);
3860 }
3861
3862 if (state->includeStack.empty() && oldFileDef)
3863 {
3864 PreIncludeInfo *ii = state->includeRelations.find(absIncFileName);
3865 if (ii==nullptr)
3866 {
3867 bool ambig = false;
3868 FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
3869 ii = state->includeRelations.add(absIncFileName,
3870 oldFileDef,
3871 ambig ? nullptr : incFd,
3872 incFileName,
3873 localInclude,
3874 state->isImported
3875 );
3876 }
3877 }
3878
3880 {
3881 for (i=0;i<state->includeStack.size();i++)
3882 {
3884 }
3885 if (alreadyProcessed)
3886 {
3887 Debug::print(Debug::Preprocessor,0,"#include {}: already processed! skipping...\n",incFileName);
3888 }
3889 else
3890 {
3891 Debug::print(Debug::Preprocessor,0,"#include {}: not found! skipping...\n",incFileName);
3892 }
3893 //printf("error: include file %s not found\n",yytext);
3894 }
3895 if (localInclude && !state->includeStack.empty() && state->curlyCount>0 && !alreadyProcessed) // failed to find #include inside { ... }
3896 {
3897 warn(state->fileName,state->yyLineNr,"include file {} not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName);
3898 }
3899 }
3900 }
3901}
3902
3903/* ----------------------------------------------------------------- */
3904
3905static void startCondSection(yyscan_t yyscanner,const QCString &sectId)
3906{
3907 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3908 //printf("startCondSection: skip=%d stack=%d\n",state->skip,state->condStack.size());
3909 CondParser prs;
3910 bool expResult = prs.parse(state->fileName.data(),state->yyLineNr,sectId.data());
3911 state->condStack.emplace(std::make_unique<preYY_CondCtx>(state->fileName,state->yyLineNr,sectId,state->skip));
3912 if (!expResult)
3913 {
3914 state->skip=TRUE;
3915 }
3916 //printf(" expResult=%d skip=%d\n",expResult,state->skip);
3917}
3918
3919static void endCondSection(yyscan_t yyscanner)
3920{
3921 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3922 if (state->condGuardCount>0 && state->condGuardErrorLine==0)
3923 {
3924 state->condGuardErrorLine = state->yyLineNr;
3925 state->condGuardErrorFileName = state->fileName;
3926 state->condGuardErrorMessage = "more #if's than #endif's in \\cond..\\endcond section";
3927 }
3928 else if (state->condGuardCount<0 && state->condGuardErrorLine==0)
3929 {
3930 state->condGuardErrorLine = state->yyLineNr;
3931 state->condGuardErrorFileName = state->fileName;
3932 state->condGuardErrorMessage = "more #endif's than #if's in \\cond..\\endcond section";
3933 }
3934 else // balanced again -> no error
3935 {
3936 state->condGuardErrorLine = 0;
3937 }
3938 if (state->condStack.empty())
3939 {
3940 warn(state->fileName,state->yyLineNr,"the \\endcond does not have a corresponding \\cond in this file");
3941 state->skip=FALSE;
3942 }
3943 else
3944 {
3945 const std::unique_ptr<preYY_CondCtx> &ctx = state->condStack.top();
3946 state->skip=ctx->skip;
3947 state->condStack.pop();
3948 }
3949 //printf("endCondSection: skip=%d stack=%d\n",state->skip,state->condStack.count());
3950}
3951
3952static void forceEndCondSection(yyscan_t yyscanner)
3953{
3954 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3955 while (!state->condStack.empty())
3956 {
3957 state->condStack.pop();
3958 }
3959 state->skip=FALSE;
3960}
3961
3962static QCString escapeAt(const QCString &text)
3963{
3964 QCString result;
3965 if (!text.isEmpty())
3966 {
3967 char c = 0;
3968 const char *p=text.data();
3969 while ((c=*p++))
3970 {
3971 if (c=='@') result+="@@"; else result+=c;
3972 }
3973 }
3974 return result;
3975}
3976
3977static char resolveTrigraph(char c)
3978{
3979 switch (c)
3980 {
3981 case '=': return '#';
3982 case '/': return '\\';
3983 case '\'': return '^';
3984 case '(': return '[';
3985 case ')': return ']';
3986 case '!': return '|';
3987 case '<': return '{';
3988 case '>': return '}';
3989 case '-': return '~';
3990 }
3991 return '?';
3992}
3993
3994/*@ ----------------------------------------------------------------------------
3995 */
3996
3997static int getNextChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint32_t &pos)
3998{
3999 //printf("getNextChar(%s,%s,%d)\n",qPrint(expr),rest ? rest->data() : 0,pos);
4000 if (pos<expr.length())
4001 {
4002 //printf(" expr()='%c'\n",expr.at(pos));
4003 return expr.at(pos++);
4004 }
4005 else if (rest && !rest->isEmpty())
4006 {
4007 int cc=rest->at(0);
4008 *rest=rest->right(rest->length()-1);
4009 //printf(" rest='%c'\n",cc);
4010 return cc;
4011 }
4012 else
4013 {
4014 int cc=yyinput(yyscanner);
4015 //printf(" yyinput()='%c' %d\n",cc,EOF);
4016 return cc;
4017 }
4018}
4019
4020static int getCurrentChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint32_t pos)
4021{
4022 //printf("getCurrentChar(%s,%s,%d)\n",qPrint(expr),rest ? rest->data() : 0,pos);
4023 if (pos<expr.length())
4024 {
4025 //printf("%c=expr()\n",expr.at(pos));
4026 return expr.at(pos);
4027 }
4028 else if (rest && !rest->isEmpty())
4029 {
4030 int cc=rest->at(0);
4031 //printf("%c=rest\n",cc);
4032 return cc;
4033 }
4034 else
4035 {
4036 int cc=yyinput(yyscanner);
4037 returnCharToStream(yyscanner,(char)cc);
4038 //printf("%c=yyinput()\n",cc);
4039 return cc;
4040 }
4041}
4042
4043static void unputChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uint32_t &pos,char c)
4044{
4045 //printf("unputChar(%s,%s,%d,%c)\n",qPrint(expr),rest ? rest->data() : 0,pos,c);
4046 if (pos<expr.length())
4047 {
4048 pos++;
4049 }
4050 else if (rest)
4051 {
4052 //printf(" prepending '%c' to rest!\n",c);
4053 char cs[2];cs[0]=c;cs[1]='\0';
4054 rest->prepend(cs);
4055 }
4056 else
4057 {
4058 //printf(" yyunput()='%c'\n",c);
4059 returnCharToStream(yyscanner,c);
4060 }
4061 //printf("result: unputChar(%s,%s,%d,%c)\n",qPrint(expr),rest ? rest->data() : 0,pos,c);
4062}
4063
4064/** Returns a reference to a Define object given its name or 0 if the Define does
4065 * not exist.
4066 */
4067static Define *isDefined(yyscan_t yyscanner,const QCString &name)
4068{
4069 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
4070
4071 bool undef = false;
4072 auto findDefine = [&undef,&name](DefineMap &map)
4073 {
4074 Define *d=nullptr;
4075 auto it = map.find(name.str());
4076 if (it!=map.end())
4077 {
4078 d = &it->second;
4079 if (d->undef)
4080 {
4081 undef=true;
4082 d=nullptr;
4083 }
4084 }
4085 return d;
4086 };
4087
4088 Define *def = findDefine(state->localDefines);
4089 if (def==nullptr && !undef)
4090 {
4091 def = findDefine(state->contextDefines);
4092 }
4093 return def;
4094}
4095
4096static void initPredefined(yyscan_t yyscanner,const QCString &fileName)
4097{
4098 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
4099
4100 // add predefined macros
4101 const StringVector &predefList = Config_getList(PREDEFINED);
4102 for (const auto &ds : predefList)
4103 {
4104 size_t i_equals=ds.find('=');
4105 size_t i_obrace=ds.find('(');
4106 size_t i_cbrace=ds.find(')');
4107 bool nonRecursive = i_equals!=std::string::npos && i_equals>0 && ds[i_equals-1]==':';
4108
4109 if ((i_obrace==0) || (i_equals==0) || (i_equals==1 && ds[i_equals-1]==':'))
4110 {
4111 continue; // no define name
4112 }
4113
4114 if (i_obrace<i_equals && i_cbrace<i_equals &&
4115 i_obrace!=std::string::npos && i_cbrace!=std::string::npos &&
4116 i_obrace<i_cbrace
4117 ) // predefined function macro definition
4118 {
4119 static const reg::Ex reId(R"(\a\w*)");
4120 std::map<std::string,int> argMap;
4121 std::string args = ds.substr(i_obrace+1,i_cbrace-i_obrace-1); // part between ( and )
4122 bool hasVarArgs = args.find("...")!=std::string::npos;
4123 //printf("predefined function macro '%s'\n",qPrint(ds));
4124 int count = 0;
4125 reg::Iterator arg_it(args,reId,0);
4126 reg::Iterator arg_end;
4127 // gather the formal arguments in a dictionary
4128 for (; arg_it!=arg_end; ++arg_it)
4129 {
4130 argMap.emplace(arg_it->str(),count++);
4131 }
4132 if (hasVarArgs) // add the variable argument if present
4133 {
4134 argMap.emplace("__VA_ARGS__",count++);
4135 }
4136
4137 // strip definition part
4138 std::string definition;
4139 std::string in=ds.substr(i_equals+1);
4140 reg::Iterator re_it(in,reId);
4141 reg::Iterator re_end;
4142 size_t i=0;
4143 // substitute all occurrences of formal arguments by their
4144 // corresponding markers
4145 for (; re_it!=re_end; ++re_it)
4146 {
4147 const auto &match = *re_it;
4148 size_t pi = match.position();
4149 size_t l = match.length();
4150 if (pi>i) definition+=in.substr(i,pi-i);
4151
4152 auto it = argMap.find(match.str());
4153 if (it!=argMap.end())
4154 {
4155 int argIndex = it->second;
4156 QCString marker;
4157 marker.sprintf(" @%d ",argIndex);
4158 definition+=marker.str();
4159 }
4160 else
4161 {
4162 definition+=match.str();
4163 }
4164 i=pi+l;
4165 }
4166 definition+=in.substr(i);
4167
4168 // add define definition to the dictionary of defines for this file
4169 std::string dname = ds.substr(0,i_obrace);
4170 if (!dname.empty())
4171 {
4172 Define def;
4173 def.name = dname;
4174 def.definition = definition;
4175 def.nargs = count;
4176 def.isPredefined = TRUE;
4177 def.nonRecursive = nonRecursive;
4178 def.fileDef = state->yyFileDef;
4179 def.fileName = fileName;
4180 def.varArgs = hasVarArgs;
4181 state->contextDefines.emplace(def.name.str(),def);
4182
4183 //printf("#define '%s' '%s' #nargs=%d hasVarArgs=%d\n",
4184 // qPrint(def.name),qPrint(def.definition),def.nargs,def.varArgs);
4185 }
4186 }
4187 else if (!ds.empty()) // predefined non-function macro definition
4188 {
4189 //printf("predefined normal macro '%s'\n",qPrint(ds));
4190 Define def;
4191 if (i_equals==std::string::npos) // simple define without argument
4192 {
4193 def.name = ds;
4194 def.definition = "1"; // substitute occurrences by 1 (true)
4195 }
4196 else // simple define with argument
4197 {
4198 int ine=static_cast<int>(i_equals) - (nonRecursive ? 1 : 0);
4199 def.name = ds.substr(0,ine);
4200 def.definition = ds.substr(i_equals+1);
4201 }
4202 if (!def.name.isEmpty())
4203 {
4204 def.nargs = -1;
4205 def.isPredefined = TRUE;
4206 def.nonRecursive = nonRecursive;
4207 def.fileDef = state->yyFileDef;
4208 def.fileName = fileName;
4209 state->contextDefines.emplace(def.name.str(),def);
4210 }
4211 }
4212 }
4213}
4214
4215///////////////////////////////////////////////////////////////////////////////////////////////
4216
4222
4224{
4225 YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner);
4226 FileInfo fi(dir.str());
4227 if (fi.isDir()) state->pathList.push_back(fi.absFilePath());
4228}
4229
4230Preprocessor::Preprocessor() : p(std::make_unique<Private>())
4231{
4232 preYYlex_init_extra(&p->state,&p->yyscanner);
4233 addSearchDir(".");
4234}
4235
4237{
4238 preYYlex_destroy(p->yyscanner);
4239}
4240
4241void Preprocessor::processFile(const QCString &fileName,const std::string &input,std::string &output)
4242{
4243 AUTO_TRACE("fileName={}",fileName);
4244 yyscan_t yyscanner = p->yyscanner;
4245 YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner);
4246 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
4247
4248#ifdef FLEX_DEBUG
4249 preYYset_debug(Debug::isFlagSet(Debug::Lex_pre)?1:0,yyscanner);
4250#endif
4251
4252 DebugLex debugLex(Debug::Lex_pre, __FILE__, qPrint(fileName));
4253 //printf("##########################\n%s\n####################\n",
4254 // qPrint(input));
4255
4256 state->macroExpansion = Config_getBool(MACRO_EXPANSION);
4257 state->expandOnlyPredef = Config_getBool(EXPAND_ONLY_PREDEF);
4258 state->skip=FALSE;
4259 state->curlyCount=0;
4260 state->lexRulesPart=false;
4261 state->nospaces=FALSE;
4262 state->inputBuf=&input;
4263 state->inputBufPos=0;
4264 state->outputBuf=&output;
4265 state->includeStack.clear();
4266 state->expandedDict.clear();
4267 state->contextDefines.clear();
4268 state->pragmaSet.clear();
4269 state->condGuardCount=0;
4270 state->condGuardErrorLine=0;
4271 while (!state->levelGuard.empty()) state->levelGuard.pop();
4272 while (!state->condStack.empty()) state->condStack.pop();
4273
4274 setFileName(yyscanner,fileName);
4275
4276 state->inputFileDef = state->yyFileDef;
4277 //yyextra->defineManager.startContext(state->fileName);
4278
4279 initPredefined(yyscanner,fileName);
4280
4281 state->yyLineNr = 1;
4282 state->yyColNr = 1;
4283 state->ifcount = 0;
4284
4285 BEGIN( Start );
4286
4287 state->expectGuard = guessSection(fileName).isHeader();
4288 state->guardName.clear();
4289 state->lastGuardName.clear();
4290 state->guardExpr.clear();
4291
4292 preYYlex(yyscanner);
4293
4294 while (!state->condStack.empty())
4295 {
4296 const std::unique_ptr<preYY_CondCtx> &ctx = state->condStack.top();
4297 QCString sectionInfo = " ";
4298 if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",qPrint(ctx->sectionId.stripWhiteSpace()));
4299 warn(ctx->fileName,ctx->lineNr,"Conditional section{}does not have "
4300 "a corresponding \\endcond command within this file.",sectionInfo);
4301 state->condStack.pop();
4302 }
4303 // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829)
4304 forceEndCondSection(yyscanner);
4305
4306 if (!state->levelGuard.empty())
4307 {
4308 if (yyextra->condGuardErrorLine!=0)
4309 {
4310 warn(yyextra->condGuardErrorFileName,yyextra->condGuardErrorLine,"{}",yyextra->condGuardErrorMessage);
4311 }
4312 else
4313 {
4314 warn(state->fileName,state->yyLineNr,"More #if's than #endif's found (might be in an included file).");
4315 }
4316 }
4317
4319 {
4320 std::lock_guard<std::mutex> lock(g_debugMutex);
4321 Debug::print(Debug::Preprocessor,0,"Preprocessor output of {} (size: {} bytes):\n",fileName,output.size());
4322 std::string contents;
4324 {
4325 contents=output;
4326 }
4327 else // need to add line numbers
4328 {
4329 int line=1;
4330 bool startOfLine = true;
4331 size_t content_size = output.size() +
4332 output.size()*6/40; // assuming 40 chars per line on average
4333 // and 6 chars extra for the line number
4334 contents.reserve(content_size);
4335 size_t pos=0;
4336 while (pos<output.size())
4337 {
4338 if (startOfLine)
4339 {
4340 char lineNrStr[15];
4341 snprintf(lineNrStr,15,"%05d ",line++);
4342 contents+=lineNrStr;
4343 }
4344 contents += output[pos];
4345 startOfLine = output[pos]=='\n';
4346 pos++;
4347 }
4348 }
4349 char end[2]={0,0};
4350 if (!contents.empty() && contents[contents.length()-1]!='\n')
4351 {
4352 end[0]='\n';
4353 }
4354 Debug::print(Debug::Preprocessor,0,"---------\n{}{}---------\n",contents,end);
4355 if (yyextra->contextDefines.size()>0)
4356 {
4357 Debug::print(Debug::Preprocessor,0,"Macros accessible in this file ({}):\n", fileName);
4358 Debug::print(Debug::Preprocessor,0,"---------\n");
4359 for (auto &kv : yyextra->contextDefines)
4360 {
4361 Debug::print(Debug::Preprocessor,0,"{} ",kv.second.name);
4362 }
4363 for (auto &kv : yyextra->localDefines)
4364 {
4365 Debug::print(Debug::Preprocessor,0,"{} ",kv.second.name);
4366 }
4367 Debug::print(Debug::Preprocessor,0,"\n---------\n");
4368 }
4369 else
4370 {
4371 Debug::print(Debug::Preprocessor,0,"No macros accessible in this file ({}).\n", fileName);
4372 }
4373 }
4374
4375 {
4376 std::lock_guard<std::mutex> lock(g_updateGlobals);
4377 for (const auto &inc : state->includeRelations)
4378 {
4379 auto toKind = [](bool local,bool imported) -> IncludeKind
4380 {
4381 if (local)
4382 {
4383 if (imported)
4384 {
4386 }
4388 }
4389 else if (imported)
4390 {
4392 }
4394 };
4395 if (inc->fromFileDef)
4396 {
4397 inc->fromFileDef->addIncludeDependency(inc->toFileDef,inc->includeName,toKind(inc->local,inc->imported));
4398 }
4399 if (inc->toFileDef && inc->fromFileDef)
4400 {
4401 inc->toFileDef->addIncludedByDependency(inc->fromFileDef,inc->fromFileDef->docName(),toKind(inc->local,inc->imported));
4402 }
4403 }
4404 // add the macro definition for this file to the global map
4405 Doxygen::macroDefinitions.emplace(state->fileName.str(),std::move(state->macroDefinitions));
4406 }
4407
4408 //yyextra->defineManager.endContext();
4409}
4410
4411#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:4236
void processFile(const QCString &fileName, const std::string &input, std::string &output)
Definition pre.l:4241
Preprocessor()
Definition pre.l:4230
void addSearchDir(const QCString &dir)
Definition pre.l:4223
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:2502
static int getCurrentChar(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t pos)
Definition pre.l:4020
static bool expandExpression(yyscan_t yyscanner, QCString &expr, QCString *rest, int pos, int level)
Definition pre.l:3082
#define MAX_EXPANSION_DEPTH
Definition pre.l:3048
static int getNextChar(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos)
Definition pre.l:3997
static QCString removeIdsAndMarkers(const QCString &s)
Definition pre.l:3268
static void initPredefined(yyscan_t yyscanner, const QCString &fileName)
Definition pre.l:4096
static void addSeparatorsIfNeeded(yyscan_t yyscanner, const QCString &expr, QCString &resultExpr, QCString &restExpr, int pos)
Definition pre.l:3050
static int getNextId(const QCString &expr, int p, int *l)
Definition pre.l:2994
static void returnCharToStream(yyscan_t yyscanner, char c)
Definition pre.l:2627
static void addTillEndOfString(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos, char term, QCString &arg)
Definition pre.l:2633
static void forceEndCondSection(yyscan_t yyscanner)
Definition pre.l:3952
static QCString expandVAOpt(const QCString &vaStr, bool hasOptionalArgs)
Definition pre.l:2684
static std::unique_ptr< FileState > checkAndOpenFile(yyscan_t yyscanner, const QCString &fileName, bool &alreadyProcessed)
Definition pre.l:2321
static const char * processUntilMatchingTerminator(const char *inputStr, QCString &result)
Process string or character literal.
Definition pre.l:3232
static void unputChar(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos, char c)
Definition pre.l:4043
static void processConcatOperators(QCString &expr)
Definition pre.l:2580
static QCString removeMarkers(const QCString &s)
Definition pre.l:3463
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:2736
static void skipCommentMacroName(yyscan_t yyscanner, const QCString &expr, QCString *rest, int &cc, uint32_t &j, int &len)
Definition pre.l:2652
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:4220
yyscan_t yyscanner
Definition pre.l:4219
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