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