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