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