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