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