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