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