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