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 
16 %option never-interactive
17 %option prefix="commentscanYY"
18 %option reentrant
19 %option extra-type="struct commentscanYY_state *"
20 %top{
21 #include <stdint.h>
22 // forward declare yyscan_t to improve typesafety
23 #define YY_TYPEDEF_YY_SCANNER_T
24 struct yyguts_t;
25 typedef yyguts_t *yyscan_t;
26 }
27 
28 %{
29 
30 /*
31  *        includes
32  */
33 
34 #include <map>
35 #include <stack>
36 #include <string>
37 #include <mutex>
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <assert.h>
42 #include <ctype.h>
43 
44 #include "qcstring.h"
45 #include "cite.h"
46 #include "commentscan.h"
47 #include "condparser.h"
48 #include "config.h"
49 #include "debug.h"
50 #include "docgroup.h"
51 #include "doxygen.h"
52 #include "entry.h"
53 #include "formula.h"
54 #include "language.h"
55 #include "message.h"
56 #include "parserintf.h"
57 #include "reflist.h"
58 #include "section.h"
59 #include "util.h"
60 #include "reflist.h"
61 
62 #define USE_STATE2STRING 0
63 
64 // forward declarations
65 static bool handleBrief(yyscan_t yyscanner,const QCString &, const StringVector &);
66 static bool handleFn(yyscan_t yyscanner,const QCString &, const StringVector &);
67 static bool handleDef(yyscan_t yyscanner,const QCString &, const StringVector &);
68 static bool handleOverload(yyscan_t yyscanner,const QCString &, const StringVector &);
69 static bool handleEnum(yyscan_t yyscanner,const QCString &, const StringVector &);
70 static bool handleDefGroup(yyscan_t yyscanner,const QCString &, const StringVector &);
71 static bool handleAddToGroup(yyscan_t yyscanner,const QCString &, const StringVector &);
72 static bool handleWeakGroup(yyscan_t yyscanner,const QCString &, const StringVector &);
73 static bool handleNamespace(yyscan_t yyscanner,const QCString &, const StringVector &);
74 static bool handlePackage(yyscan_t yyscanner,const QCString &, const StringVector &);
75 static bool handleConcept(yyscan_t yyscanner,const QCString &, const StringVector &);
76 static bool handleClass(yyscan_t yyscanner,const QCString &, const StringVector &);
77 static bool handleHeaderFile(yyscan_t yyscanner,const QCString &, const StringVector &);
78 static bool handleProtocol(yyscan_t yyscanner,const QCString &, const StringVector &);
79 static bool handleCategory(yyscan_t yyscanner,const QCString &, const StringVector &);
80 static bool handleUnion(yyscan_t yyscanner,const QCString &, const StringVector &);
81 static bool handleStruct(yyscan_t yyscanner,const QCString &, const StringVector &);
82 static bool handleInterface(yyscan_t yyscanner,const QCString &, const StringVector &);
83 static bool handleIdlException(yyscan_t yyscanner,const QCString &, const StringVector &);
84 static bool handlePage(yyscan_t yyscanner,const QCString &, const StringVector &);
85 static bool handleMainpage(yyscan_t yyscanner,const QCString &, const StringVector &);
86 static bool handleFile(yyscan_t yyscanner,const QCString &, const StringVector &);
87 static bool handleDir(yyscan_t yyscanner,const QCString &, const StringVector &);
88 static bool handleExample(yyscan_t yyscanner,const QCString &, const StringVector &);
89 static bool handleDetails(yyscan_t yyscanner,const QCString &, const StringVector &);
90 static bool handleRaiseWarning(yyscan_t yyscanner,const QCString &, const StringVector &);
91 static bool handleNoop(yyscan_t yyscanner,const QCString &, const StringVector &);
92 static bool handleName(yyscan_t yyscanner,const QCString &, const StringVector &);
93 static bool handleTodo(yyscan_t yyscanner,const QCString &, const StringVector &);
94 static bool handleTest(yyscan_t yyscanner,const QCString &, const StringVector &);
95 static bool handleBug(yyscan_t yyscanner,const QCString &, const StringVector &);
96 static bool handleSubpage(yyscan_t yyscanner,const QCString &s, const StringVector &);
97 static bool handleDeprecated(yyscan_t yyscanner,const QCString &, const StringVector &);
98 static bool handleXRefItem(yyscan_t yyscanner,const QCString &, const StringVector &);
99 static bool handleRelated(yyscan_t yyscanner,const QCString &, const StringVector &);
100 static bool handleRelatedAlso(yyscan_t yyscanner,const QCString &, const StringVector &);
101 static bool handleMemberOf(yyscan_t yyscanner,const QCString &, const StringVector &);
102 static bool handleRefItem(yyscan_t yyscanner,const QCString &, const StringVector &);
103 static bool handleSection(yyscan_t yyscanner,const QCString &, const StringVector &);
104 static bool handleAnchor(yyscan_t yyscanner,const QCString &, const StringVector &);
105 static bool handleImage(yyscan_t yyscanner,const QCString &, const StringVector &);
106 static bool handleCite(yyscan_t yyscanner,const QCString &, const StringVector &);
107 static bool handleFormatBlock(yyscan_t yyscanner,const QCString &, const StringVector &);
108 static bool handleAddIndex(yyscan_t yyscanner,const QCString &, const StringVector &);
109 static bool handleIf(yyscan_t yyscanner,const QCString &, const StringVector &);
110 static bool handleIfNot(yyscan_t yyscanner,const QCString &, const StringVector &);
111 static bool handleElseIf(yyscan_t yyscanner,const QCString &, const StringVector &);
112 static bool handleElse(yyscan_t yyscanner,const QCString &, const StringVector &);
113 static bool handleEndIf(yyscan_t yyscanner,const QCString &, const StringVector &);
114 static bool handleIngroup(yyscan_t yyscanner,const QCString &, const StringVector &);
115 static bool handleNoSubGrouping(yyscan_t yyscanner,const QCString &, const StringVector &);
116 static bool handleShowInitializer(yyscan_t yyscanner,const QCString &, const StringVector &);
117 static bool handleHideInitializer(yyscan_t yyscanner,const QCString &, const StringVector &);
118 static bool handleCallgraph(yyscan_t yyscanner,const QCString &, const StringVector &);
119 static bool handleHideCallgraph(yyscan_t yyscanner,const QCString &, const StringVector &);
120 static bool handleCallergraph(yyscan_t yyscanner,const QCString &, const StringVector &);
121 static bool handleHideCallergraph(yyscan_t yyscanner,const QCString &, const StringVector &);
122 static bool handleReferencedByRelation(yyscan_t yyscanner,const QCString &, const StringVector &);
123 static bool handleHideReferencedByRelation(yyscan_t yyscanner,const QCString &, const StringVector &);
124 static bool handleReferencesRelation(yyscan_t yyscanner,const QCString &, const StringVector &);
125 static bool handleHideReferencesRelation(yyscan_t yyscanner,const QCString &, const StringVector &);
126 static bool handleInternal(yyscan_t yyscanner,const QCString &, const StringVector &);
127 static bool handleStatic(yyscan_t yyscanner,const QCString &, const StringVector &);
128 static bool handlePure(yyscan_t yyscanner,const QCString &, const StringVector &);
129 static bool handlePrivate(yyscan_t yyscanner,const QCString &, const StringVector &);
130 static bool handlePrivateSection(yyscan_t yyscanner,const QCString &, const StringVector &);
131 static bool handleProtected(yyscan_t yyscanner,const QCString &, const StringVector &);
132 static bool handleProtectedSection(yyscan_t yyscanner,const QCString &, const StringVector &);
133 static bool handlePublic(yyscan_t yyscanner,const QCString &s, const StringVector &);
134 static bool handlePublicSection(yyscan_t yyscanner,const QCString &s, const StringVector &);
135 static bool handleToc(yyscan_t yyscanner,const QCString &s, const StringVector &);
136 static bool handleInherit(yyscan_t yyscanner,const QCString &, const StringVector &);
137 static bool handleExtends(yyscan_t yyscanner,const QCString &, const StringVector &);
138 static bool handleCopyDoc(yyscan_t yyscanner,const QCString &, const StringVector &);
139 static bool handleCopyBrief(yyscan_t yyscanner,const QCString &, const StringVector &);
140 static bool handleCopyDetails(yyscan_t yyscanner,const QCString &, const StringVector &);
141 static bool handleParBlock(yyscan_t yyscanner,const QCString &, const StringVector &);
142 static bool handleEndParBlock(yyscan_t yyscanner,const QCString &, const StringVector &);
143 static bool handleParam(yyscan_t yyscanner,const QCString &, const StringVector &);
144 static bool handleRetval(yyscan_t yyscanner,const QCString &, const StringVector &);
145 
146 #if USE_STATE2STRING
147 static const char *stateToString(int state);
148 #endif
149 
150 typedef bool (*DocCmdFunc)(yyscan_t yyscanner,const QCString &name, const StringVector &optList);
151 
152 enum class CommandSpacing
153 {
154   Invisible, // command sets some property but does not appear in the output.
155   Inline,    // command appears inline in the output which can be a brief description.
156   Block,     // command starts a new paragraphs / ends a brief description.
157   XRef       // command is a cross reference (todo, bug, test, xrefitem).
158 };
159 
160 struct DocCmdMap
161 {
DocCmdMapDocCmdMap162   DocCmdMap(DocCmdFunc h,CommandSpacing s) : handler(h), spacing(s) {}
163   DocCmdFunc handler;
164   CommandSpacing spacing;
165 };
166 
167 // map of command to handler function
168 static const std::map< std::string, DocCmdMap > docCmdMap =
169 {
170   // command name      handler function           command spacing
171   { "addindex",        { &handleAddIndex,         CommandSpacing::Invisible }},
172   { "addtogroup",      { &handleAddToGroup,       CommandSpacing::Invisible }},
173   { "anchor",          { &handleAnchor,           CommandSpacing::Invisible }},
174   { "arg",             { 0,                       CommandSpacing::Block     }},
175   { "attention",       { 0,                       CommandSpacing::Block     }},
176   { "author",          { 0,                       CommandSpacing::Block     }},
177   { "authors",         { 0,                       CommandSpacing::Block     }},
178   { "brief",           { &handleBrief,            CommandSpacing::Invisible }},
179   { "bug",             { &handleBug,              CommandSpacing::XRef      }},
180   { "callergraph",     { &handleCallergraph,      CommandSpacing::Invisible }},
181   { "callgraph",       { &handleCallgraph,        CommandSpacing::Invisible }},
182   { "category",        { &handleCategory,         CommandSpacing::Invisible }},
183   { "cite",            { &handleCite,             CommandSpacing::Inline    }},
184   { "class",           { &handleClass,            CommandSpacing::Invisible }},
185   { "code",            { &handleFormatBlock,      CommandSpacing::Block     }},
186   { "concept",         { &handleConcept,          CommandSpacing::Invisible }},
187   { "copybrief",       { &handleCopyBrief,        CommandSpacing::Invisible }},
188   { "copydetails",     { &handleCopyDetails,      CommandSpacing::Block     }},
189   { "copydoc",         { &handleCopyDoc,          CommandSpacing::Block     }},
190   { "copyright",       { 0,                       CommandSpacing::Block     }},
191   { "date",            { 0,                       CommandSpacing::Block     }},
192   { "def",             { &handleDef,              CommandSpacing::Invisible }},
193   { "defgroup",        { &handleDefGroup,         CommandSpacing::Invisible }},
194   { "deprecated",      { &handleDeprecated,       CommandSpacing::XRef      }},
195   { "details",         { &handleDetails,          CommandSpacing::Block     }},
196   { "dir",             { &handleDir,              CommandSpacing::Invisible }},
197   { "docbookinclude",  { 0,                       CommandSpacing::Inline    }},
198   { "docbookonly",     { &handleFormatBlock,      CommandSpacing::Invisible }},
199   { "dot",             { &handleFormatBlock,      CommandSpacing::Block     }},
200   { "dotfile",         { 0,                       CommandSpacing::Block     }},
201   { "else",            { &handleElse,             CommandSpacing::Inline    }},
202   { "elseif",          { &handleElseIf,           CommandSpacing::Inline    }},
203   { "endif",           { &handleEndIf,            CommandSpacing::Inline    }},
204   { "endparblock",     { &handleEndParBlock,      CommandSpacing::Block     }},
205   { "enum",            { &handleEnum,             CommandSpacing::Invisible }},
206   { "example",         { &handleExample,          CommandSpacing::Invisible }},
207   { "exception",       { 0,                       CommandSpacing::Block     }},
208   { "extends",         { &handleExtends,          CommandSpacing::Invisible }},
209   { "file",            { &handleFile,             CommandSpacing::Invisible }},
210   { "fn",              { &handleFn,               CommandSpacing::Invisible }},
211   { "headerfile",      { &handleHeaderFile,       CommandSpacing::Invisible }},
212   { "hidecallergraph", { &handleHideCallergraph,  CommandSpacing::Invisible }},
213   { "hidecallgraph",   { &handleHideCallgraph,    CommandSpacing::Invisible }},
214   { "hideinitializer", { &handleHideInitializer,  CommandSpacing::Invisible }},
215   { "hiderefby",       { &handleHideReferencedByRelation, CommandSpacing::Invisible }},
216   { "hiderefs",        { &handleHideReferencesRelation,   CommandSpacing::Invisible }},
217   { "htmlinclude",     { 0,                       CommandSpacing::Inline    }},
218   { "htmlonly",        { &handleFormatBlock,      CommandSpacing::Invisible }},
219   { "idlexcept",       { &handleIdlException,     CommandSpacing::Invisible }},
220   { "if",              { &handleIf,               CommandSpacing::Inline    }},
221   { "ifnot",           { &handleIfNot,            CommandSpacing::Inline    }},
222   { "image",           { &handleImage,            CommandSpacing::Block     }},
223   { "implements",      { &handleExtends,          CommandSpacing::Invisible }},
224   { "include",         { 0,                       CommandSpacing::Block     }},
225   { "includelineno",   { 0,                       CommandSpacing::Block     }},
226   { "ingroup",         { &handleIngroup,          CommandSpacing::Invisible }},
227   { "inherit",         { &handleInherit,          CommandSpacing::Invisible }},
228   { "interface",       { &handleInterface,        CommandSpacing::Invisible }},
229   { "internal",        { &handleInternal,         CommandSpacing::Block     }},
230   { "invariant",       { 0,                       CommandSpacing::Block     }},
231   { "latexinclude",    { 0,                       CommandSpacing::Inline    }},
232   { "latexonly",       { &handleFormatBlock,      CommandSpacing::Invisible }},
233   { "li",              { 0,                       CommandSpacing::Block     }},
234   { "line",            { 0,                       CommandSpacing::Invisible }},
235   { "mainpage",        { &handleMainpage,         CommandSpacing::Invisible }},
236   { "maninclude",      { 0,                       CommandSpacing::Inline    }},
237   { "manonly",         { &handleFormatBlock,      CommandSpacing::Invisible }},
238   { "memberof",        { &handleMemberOf,         CommandSpacing::Invisible }},
239   { "msc",             { &handleFormatBlock,      CommandSpacing::Block     }},
240   { "name",            { &handleName,             CommandSpacing::Invisible }},
241   { "namespace",       { &handleNamespace,        CommandSpacing::Invisible }},
242   { "noop",            { &handleNoop,             CommandSpacing::Invisible }},
243   { "nosubgrouping",   { &handleNoSubGrouping,    CommandSpacing::Invisible }},
244   { "note",            { 0,                       CommandSpacing::Block     }},
245   { "overload",        { &handleOverload,         CommandSpacing::Invisible }},
246   { "package",         { &handlePackage,          CommandSpacing::Invisible }},
247   { "page",            { &handlePage,             CommandSpacing::Invisible }},
248   { "par",             { 0,                       CommandSpacing::Block     }},
249   { "paragraph",       { &handleSection,          CommandSpacing::Block     }},
250   { "param",           { &handleParam,            CommandSpacing::Block     }},
251   { "parblock",        { &handleParBlock,         CommandSpacing::Block     }},
252   { "post",            { 0,                       CommandSpacing::Block     }},
253   { "pre",             { 0,                       CommandSpacing::Block     }},
254   { "private",         { &handlePrivate,          CommandSpacing::Invisible }},
255   { "privatesection",  { &handlePrivateSection,   CommandSpacing::Invisible }},
256   { "property",        { &handleFn,               CommandSpacing::Invisible }},
257   { "protected",       { &handleProtected,        CommandSpacing::Invisible }},
258   { "protectedsection",{ &handleProtectedSection, CommandSpacing::Invisible }},
259   { "protocol",        { &handleProtocol,         CommandSpacing::Invisible }},
260   { "public",          { &handlePublic,           CommandSpacing::Invisible }},
261   { "publicsection",   { &handlePublicSection,    CommandSpacing::Invisible }},
262   { "pure",            { &handlePure,             CommandSpacing::Invisible }},
263   { "raisewarning",    { &handleRaiseWarning,     CommandSpacing::Invisible }},
264   { "refitem",         { &handleRefItem,          CommandSpacing::Inline    }},
265   { "related",         { &handleRelated,          CommandSpacing::Invisible }},
266   { "relatedalso",     { &handleRelatedAlso,      CommandSpacing::Invisible }},
267   { "relates",         { &handleRelated,          CommandSpacing::Invisible }},
268   { "relatesalso",     { &handleRelatedAlso,      CommandSpacing::Invisible }},
269   { "remark",          { 0,                       CommandSpacing::Block     }},
270   { "remarks",         { 0,                       CommandSpacing::Block     }},
271   { "result",          { 0,                       CommandSpacing::Block     }},
272   { "return",          { 0,                       CommandSpacing::Block     }},
273   { "returns",         { 0,                       CommandSpacing::Block     }},
274   { "retval",          { &handleRetval,           CommandSpacing::Block     }},
275   { "rtfinclude",      { 0,                       CommandSpacing::Inline    }},
276   { "rtfonly",         { &handleFormatBlock,      CommandSpacing::Invisible }},
277   { "sa",              { 0,                       CommandSpacing::Block     }},
278   { "section",         { &handleSection,          CommandSpacing::Block     }},
279   { "see",             { 0,                       CommandSpacing::Block     }},
280   { "short",           { &handleBrief,            CommandSpacing::Invisible }},
281   { "showinitializer", { &handleShowInitializer,  CommandSpacing::Invisible }},
282   { "showrefby",       { &handleReferencedByRelation,     CommandSpacing::Invisible }},
283   { "showrefs",        { &handleReferencesRelation,       CommandSpacing::Invisible }},
284   { "since",           { 0,                       CommandSpacing::Block     }},
285   { "snippet",         { 0,                       CommandSpacing::Block     }},
286   { "snippetlineno",   { 0,                       CommandSpacing::Block     }},
287   { "startuml",        { &handleFormatBlock,      CommandSpacing::Block     }},
288   { "static",          { &handleStatic,           CommandSpacing::Invisible }},
289   { "struct",          { &handleStruct,           CommandSpacing::Invisible }},
290   { "subpage",         { &handleSubpage,          CommandSpacing::Inline    }},
291   { "subsection",      { &handleSection,          CommandSpacing::Block     }},
292   { "subsubsection",   { &handleSection,          CommandSpacing::Block     }},
293   { "tableofcontents", { &handleToc,              CommandSpacing::Invisible }},
294   { "test",            { &handleTest,             CommandSpacing::XRef      }},
295   { "throw",           { 0,                       CommandSpacing::Block     }},
296   { "throws",          { 0,                       CommandSpacing::Block     }},
297   { "todo",            { &handleTodo,             CommandSpacing::XRef      }},
298   { "tparam",          { 0,                       CommandSpacing::Block     }},
299   { "typedef",         { &handleFn,               CommandSpacing::Invisible }},
300   { "union",           { &handleUnion,            CommandSpacing::Invisible }},
301   { "until",           { 0,                       CommandSpacing::Block     }},
302   { "var",             { &handleFn,               CommandSpacing::Invisible }},
303   { "verbatim",        { &handleFormatBlock,      CommandSpacing::Block     }},
304   { "verbinclude",     { 0,                       CommandSpacing::Inline    }},
305   { "version",         { 0,                       CommandSpacing::Block     }},
306   { "warning",         { 0,                       CommandSpacing::Block     }},
307   { "weakgroup",       { &handleWeakGroup,        CommandSpacing::Invisible }},
308   { "xmlinclude",      { 0,                       CommandSpacing::Inline    }},
309   { "xmlonly",         { &handleFormatBlock,      CommandSpacing::Invisible }},
310   { "xrefitem",        { &handleXRefItem,         CommandSpacing::XRef      }},
311   { "iliteral",        { &handleFormatBlock,      CommandSpacing::Inline    }},
312 };
313 
314 #define YY_NO_INPUT 1
315 #define YY_NO_UNISTD_H 1
316 #define YY_NEVER_INTERACTIVE 1
317 
318 
319 enum XRefKind
320 {
321   XRef_Item,
322   XRef_Todo,
323   XRef_Test,
324   XRef_Bug,
325   XRef_Deprecated,
326   XRef_None
327 };
328 
329 enum OutputContext
330 {
331   OutputDoc,
332   OutputBrief,
333   OutputXRef,
334   OutputInbody
335 };
336 
337 enum GuardType
338 {
339   Guard_If,
340   Guard_IfNot,
341   Guard_Skip
342 };
343 
344 class GuardedSection
345 {
346   public:
GuardedSection(bool enabled,bool parentVisible)347     GuardedSection(bool enabled,bool parentVisible)
348       : m_enabled(enabled),m_parentVisible(parentVisible) {}
isEnabled()349     bool isEnabled() const { return m_enabled; }
parentVisible()350     bool parentVisible() const { return m_parentVisible; }
351 
352   private:
353     bool m_enabled;
354     bool m_parentVisible;
355 };
356 
357 /* -----------------------------------------------------------------
358  *
359  *        statics
360  */
361 
362 struct commentscanYY_state
363 {
364   OutlineParserInterface *langParser = 0;  // the language parser that is calling us
365   QCString         inputString;            // input string
366   QCString         currentCmd;             // the command used
367   int              inputPosition = 0;      // read pointer
368   QCString         fileName;               // file name that is read from
369   int              lineNr = 0;             // line number in the input
370   bool             inBody = FALSE;         // was the comment found inside the body of a function?
371   OutputContext    inContext;              // are we inside the brief, details or xref part
372   bool             briefEndsAtDot = FALSE; // does the brief description stop at a dot?
373   QCString         formulaText;            // Running text of a formula
374   QCString         formulaEnv;             // environment name
375   int              formulaNewLines = 0;    // amount of new lines in the formula
376   QCString        *pOutputString = 0;      // pointer to string to which the output is appended.
377   QCString         outputXRef;               // temp argument of todo/test/../xrefitem commands
378   QCString         blockName;                // preformatted block name (e.g. verbatim, latexonly,...)
379   XRefKind         xrefKind    = XRef_Item;  // kind of cross-reference command
380   XRefKind         newXRefKind = XRef_Item;  //
381   GuardType        guardType = Guard_If;     // kind of guards for conditional section
382   bool             enabledSectionFound = FALSE;
383   QCString         functionProto;          // function prototype
384   std::stack<GuardedSection> guards;             // tracks nested conditional sections (if,ifnot,..)
385   Entry           *current = 0;              // working entry
386 
387   bool             needNewEntry = FALSE;
388 
389   QCString         sectionLabel;
390   QCString         sectionTitle;
391   int              sectionLevel = 0;
392   QCString         xrefItemKey;
393   QCString         newXRefItemKey;
394   QCString         xrefItemTitle;
395   QCString         xrefListTitle;
396   Protection       protection = Public;
397 
398   bool             xrefAppendFlag = FALSE;
399   bool             inGroupParamFound = FALSE;
400   int              braceCount = 0;
401   bool             insidePre = FALSE;
402   bool             parseMore = FALSE;
403   int              condCount = 0;
404 
405   int              commentCount = 0;
406   QCString         spaceBeforeCmd;
407   QCString         spaceBeforeIf;
408   QCString         copyDocArg;
409 
410   QCString         guardExpr;
411   int              roundCount = 0;
412   int              HTMLDetails = 0;
413 
414   bool             insideParBlock = FALSE;
415   bool             inInternalDocs = FALSE;
416   int              prevPosition = 0;
417   DocGroup         docGroup;
418   bool             markdownSupport = TRUE;
419 
420   QCString         raiseWarning;
421 };
422 
423 
424 static std::mutex g_sectionMutex;
425 static std::mutex g_formulaMutex;
426 static std::mutex g_citeMutex;
427 
428 //-----------------------------------------------------------------------------
429 
430 static QCString stripQuotes(const char *s);
431 static bool getDocSectionName(int s);
432 static SectionType sectionLevelToType(int level);
433 static void stripTrailingWhiteSpace(QCString &s);
434 
435 static void initParser(yyscan_t yyscanner);
436 static bool makeStructuralIndicator(yyscan_t yyscanner,Entry::Sections s);
437 static void lineCount(yyscan_t yyscanner);
438 static void addXRefItem(yyscan_t yyscanner,
439                         const QCString &listName,const QCString &itemTitle,
440                         const QCString &listTitle,bool append);
441 static QCString addFormula(yyscan_t yyscanner);
442 static void checkFormula(yyscan_t yyscanner);
443 static void addSection(yyscan_t yyscanner);
444 static inline void setOutput(yyscan_t yyscanner,OutputContext ctx);
445 static void addAnchor(yyscan_t yyscanner,const QCString &anchor);
446 static inline void addOutput(yyscan_t yyscanner,const char *s);
447 static inline void addOutput(yyscan_t yyscanner,const QCString &s);
448 static inline void addOutput(yyscan_t yyscanner,char c);
449 static void endBrief(yyscan_t yyscanner,bool addToOutput=TRUE);
450 static void handleGuard(yyscan_t yyscanner,const QCString &expr);
451 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
452 static void addCite(yyscan_t yyscanner);
453 static void addIline(yyscan_t yyscanner,int lineNr);
454 
455 #define unput_string(yytext,yyleng) do { for (int i=(int)yyleng-1;i>=0;i--) unput(yytext[i]); } while(0)
456 
457 //-----------------------------------------------------------------------------
458 
459 #undef        YY_INPUT
460 #define        YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
461 
462 // otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
getLexerFILE()463 static inline const char *getLexerFILE() {return __FILE__;}
464 #include "doxygen_lex.h"
465 
466 %}
467 
468        /* start command character */
469 CMD          ("\\"|"@")
470 XREFCMD   {CMD}("bug"|"deprecated"|"test"|"todo"|"xrefitem")
471 PRE       [pP][rR][eE]
472 TABLE          [tT][aA][bB][lL][eE]
473 P          [pP]
474 UL        [uU][lL]
475 OL          [oO][lL]
476 DL          [dD][lL]
477 IMG       [iI][mM][gG]
478 HR        [hH][rR]
479 PARA      [pP][aA][rR][aA]
480 CODE      [cC][oO][dD][eE]
481 CAPTION   [cC][aA][pP][tT][iI][oO][nN]
482 CENTER    [cC][eE][nN][tT][eE][rR]
483 DIV       [dD][iI][vV]
484 DETAILS   [dD][eE][tT][aA][iI][lL][sS]
485 DETAILEDHTML {CENTER}|{DIV}|{PRE}|{UL}|{TABLE}|{OL}|{DL}|{P}|[Hh][1-6]|{IMG}|{HR}|{PARA}
486 DETAILEDHTMLOPT {CODE}
487 SUMMARY   [sS][uU][mM][mM][aA][rR][yY]
488 REMARKS   [rR][eE][mM][aA][rR][kK][sS]
489 BN        [ \t\n\r]
490 BL        [ \t\r]*"\n"
491 B         [ \t]
492 Bopt      {B}*
493 BS        ^(({B}*"/""/")?)(({B}*"*"+)?){B}*
494 ATTR      ({B}+[^>\n]*)?
495 DOCNL     "\n"|"\\ilinebr"
496 LC        "\\"{B}*"\n"
497 NW          [^a-z_A-Z0-9]
498 FILESCHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+@&#]
499 FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+@&#]
500 FILE      ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|("\""[^\n\"]*"\"")
501 ID        [$a-z_A-Z\x80-\xFF][$a-z_A-Z0-9\x80-\xFF]*
502 LABELID   [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-]*
503 CITESCHAR [a-z_A-Z0-9\x80-\xFF\-\?]
504 CITEECHAR [a-z_A-Z0-9\x80-\xFF\-\+:\/\?]*
505 CITEID    {CITESCHAR}{CITEECHAR}*("."{CITESCHAR}{CITEECHAR}*)*|"\""{CITESCHAR}{CITEECHAR}*("."{CITESCHAR}{CITEECHAR}*)*"\""
506 SCOPEID   {ID}({ID}*{BN}*"::"{BN}*)*({ID}?)
507 SCOPENAME "$"?(({ID}?{BN}*("::"|"."){BN}*)*)((~{BN}*)?{ID})
508 TMPLSPEC  "<"{BN}*[^>]+{BN}*">"
509 MAILADDR  ("mailto:")?[a-z_A-Z0-9\x80-\xff.+-]+"@"[a-z_A-Z0-9\x80-\xff-]+("."[a-z_A-Z0-9\x80-\xff\-]+)+[a-z_A-Z0-9\x80-\xff\-]+
510 RCSTAG    "$"{ID}":"[^\n$]+"$"
511 
512   // C start comment
513 CCS   "/\*"
514   // C end comment
515 CCE   "*\/"
516   // Cpp comment
517 CPPC  "/\/"
518 
519   // end of section title with asterisk
520 STAopt [^\n@\\*]*
521   // end of section title without asterisk
522 STopt  [^\n@\\]*
523 
524 %option noyywrap
525 
526   /* comment parsing states. */
527 %x      Comment
528 %x      PageDocArg1
529 %x      PageDocArg2
530 %x      RelatesParam1
531 %x      ClassDocArg1
532 %x      ClassDocArg2
533 %x      ClassDocArg3
534 %x      CategoryDocArg1
535 %x      XRefItemParam1
536 %x      XRefItemParam2
537 %x      XRefItemParam3
538 %x      FileDocArg1
539 %x      ParamArg1
540 %x      EnumDocArg1
541 %x      NameSpaceDocArg1
542 %x      PackageDocArg1
543 %x      ConceptDocArg1
544 %x      GroupDocArg1
545 %x      GroupDocArg2
546 %x      SectionLabel
547 %x      SectionTitle
548 %x      SubpageLabel
549 %x      SubpageTitle
550 %x      FormatBlock
551 %x      LineParam
552 %x      GuardParam
553 %x      GuardParamEnd
554 %x      SkipGuardedSection
555 %x      SkipInternal
556 %x      NameParam
557 %x      InGroupParam
558 %x      FnParam
559 %x      OverloadParam
560 %x      InheritParam
561 %x      ExtendsParam
562 %x      ReadFormulaShort
563 %x      ReadFormulaRound
564 %x      ReadFormulaLong
565 %x      AnchorLabel
566 %x      HtmlComment
567 %x      SkipLang
568 %x      CiteLabel
569 %x      CopyDoc
570 %x      GuardExpr
571 %x      CdataSection
572 %x      Noop
573 %x      RaiseWarning
574 
575 %%
576 
577   /* What can happen in while parsing a comment block:
578    *   commands (e.g. @page, or \page)
579    *   escaped commands (e.g. @@page or \\page).
580    *   formulas (e.g. \f$...\f$ \f[...\f] \f{...\f} \f(...\f) )
581    *   directories (e.g. \doxygen\src\)
582    *   autolist end. (e.g. a dot on an otherwise empty line)
583    *   newlines.
584    *   end of brief description due to blank line.
585    *   end of brief description due to some command (@command, or <command>).
586    *   words and whitespace and other characters (#,?!, etc).
587    *   grouping commands (e.g. @{ and @})
588    *   language switch (e.g. \~english or \~).
589    *   mail address (e.g. doxygen@gmail.com).
590    *   quoted text, such as "foo@bar"
591    *   XML commands, <summary></summary><remarks></remarks>
592    */
593 
594 <Comment>{CMD}{CMD}[a-z_A-Z]+{B}*       { // escaped command
595                                           addOutput(yyscanner,yytext);
596                                         }
597 <Comment>{CMD}{CMD}"~"[a-z_A-Z]*        { // escaped command
598                                           addOutput(yyscanner,yytext);
599                                         }
600 <Comment>{MAILADDR}                     { // mail address
601                                           addOutput(yyscanner,yytext);
602                                         }
603 <Comment>"\""[^"\n]*"\""                { // quoted text
604                                           addOutput(yyscanner,yytext);
605                                         }
606 <Comment>("\\"[a-z_A-Z]+)+"\\"          { // directory (or chain of commands!)
607                                           addOutput(yyscanner,yytext);
608                                         }
609 <Comment>"<"{DETAILEDHTML}{ATTR}">"     { // HTML command that ends a brief description
610                                           setOutput(yyscanner,OutputDoc);
611                                           // continue with the same input
612                                           REJECT;
613                                         }
614 <Comment>"<"{DETAILEDHTMLOPT}{ATTR}">"  { // HTML command that ends a brief description
615                                           if (yyextra->current->lang==SrcLangExt_CSharp)
616                                           {
617                                             setOutput(yyscanner,OutputDoc);
618                                           }
619                                           // continue with the same input
620                                           REJECT;
621                                         }
622 <Comment>"<"{DETAILS}{ATTR}">"          { // start of a HTML style details description
623                                           yyextra->HTMLDetails++;
624                                           setOutput(yyscanner,OutputDoc);
625                                           addOutput(yyscanner,yytext);
626                                         }
627 <Comment>"</"{DETAILS}">"               { // end of a HTML style details description
628                                           if (yyextra->HTMLDetails) yyextra->HTMLDetails--;
629                                           addOutput(yyscanner,yytext);
630                                         }
631 <Comment>"<"{SUMMARY}">"                { // start of a .NET XML style brief description
632                                           if (!yyextra->HTMLDetails) setOutput(yyscanner,OutputBrief);
633                                           addOutput(yyscanner,yytext);
634                                         }
635 <Comment>"<"{REMARKS}">"                { // start of a .NET XML style detailed description
636                                           setOutput(yyscanner,OutputDoc);
637                                           addOutput(yyscanner,yytext);
638                                         }
639 <Comment>"</"{SUMMARY}">"               { // start of a .NET XML style detailed description
640                                           addOutput(yyscanner,yytext);
641                                           if (!yyextra->HTMLDetails) setOutput(yyscanner,OutputDoc);
642                                         }
643 <Comment>"</"{REMARKS}">"               { // end of a brief or detailed description
644                                           setOutput(yyscanner,OutputDoc);
645                                           addOutput(yyscanner,yytext);
646                                         }
647 <Comment>"<"{CAPTION}{ATTR}">"          {
648                                           QCString tag(yytext);
649                                           int s=tag.find("id=");
650                                           if (s!=-1) // command has id attribute
651                                           {
652                                             char c=tag[s+3];
653                                             if (c=='\'' || c=='"') // valid start
654                                             {
655                                               int e=tag.find(c,s+4);
656                                               if (e!=-1) // found matching end
657                                               {
658                                                 QCString id=tag.mid(s+4,e-s-4); // extract id
659                                                 addAnchor(yyscanner,id);
660                                               }
661                                             }
662                                           }
663                                           addOutput(yyscanner,yytext);
664                                         }
665 <Comment>"<"{PRE}{ATTR}">"              {
666                                           yyextra->insidePre=TRUE;
667                                           addOutput(yyscanner,yytext);
668                                         }
669 <Comment>"</"{PRE}">"                   {
670                                           yyextra->insidePre=FALSE;
671                                           addOutput(yyscanner,yytext);
672                                         }
673 <Comment>{RCSTAG}                       { // RCS tag which end a brief description
674                                           setOutput(yyscanner,OutputDoc);
675                                           REJECT;
676                                         }
677 <Comment>"<!--"                         {
678                                           BEGIN(HtmlComment);
679                                         }
680 <Comment>"<!\[CDATA\["                  {
681                                           BEGIN(CdataSection);
682                                         }
683 <Comment>{B}*{CMD}"endinternal"{B}*     {
684                                           addOutput(yyscanner," \\endinternal ");
685                                           if (!yyextra->inInternalDocs)
686                                               warn(yyextra->fileName,yyextra->lineNr,
687                                                "found \\endinternal without matching \\internal"
688                                               );
689                                           yyextra->inInternalDocs = FALSE;
690                                         }
691 <Comment>{B}*"\\ilinebr"{B}*            { // preserve spacing around \\ilinebr
692                                           addOutput(yyscanner,yytext);
693                                         }
694 <Comment>{B}*{CMD}[a-z_A-Z]+"{"[a-zA-Z_,:0-9\. ]*"}"{B}*  |
695 <Comment>{B}*{CMD}[a-z_A-Z]+{B}*        { // potentially interesting command
696                                           // the {B}* in the front was added for bug620924
697                                           QCString fullMatch = QCString(yytext);
698                                           int idx = fullMatch.find('{');
699                                           /* handle `\f{` and `@f{` as special cases */
700                                           if ((idx > 1) && (yytext[idx-1] == 'f') && (yytext[idx-2] == '\\' || yytext[idx-2] =='@')) REJECT;
701                                           int idxEnd = fullMatch.find("}",idx+1);
702                                           QCString cmdName;
703                                           StringVector optList;
704                                           if (idx == -1) // no options
705                                           {
706                                             cmdName = QCString(yytext).stripWhiteSpace().mid(1); // to remove {CMD}
707                                           }
708                                           else // options present
709                                           {
710                                             cmdName = fullMatch.left(idx).stripWhiteSpace().mid(1); // to remove {CMD}
711                                             QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
712                                             optList = split(optStr.str(),",");
713                                           }
714                                           auto it = docCmdMap.find(cmdName.str());
715                                           //printf("lookup command '%s' found=%d\n",qPrint(cmdName),it!=docCmdMap.end());
716                                           if (it!=docCmdMap.end()) // special action is required
717                                           {
718                                             int i=0;
719                                             while (yytext[i]==' ' || yytext[i]=='\t') i++;
720                                             yyextra->spaceBeforeCmd = QCString(yytext).left(i);
721                                             CommandSpacing spacing = it->second.spacing;
722                                             if ((spacing==CommandSpacing::Block || spacing==CommandSpacing::XRef) &&
723                                                 !(yyextra->inContext==OutputXRef && cmdName=="parblock"))
724                                             {
725                                               yyextra->briefEndsAtDot=FALSE;
726                                               bool insideXRef = yyextra->inContext==OutputXRef && spacing==CommandSpacing::XRef;
727                                               // this command forces the end of brief description
728                                               setOutput(yyscanner,insideXRef ? OutputXRef : OutputDoc);
729                                             }
730                                             //if (i>0) addOutput(yyscanner,QCString(yytext).left(i)); // removed for bug 689341
731                                             if (it->second.handler && it->second.handler(yyscanner, cmdName, optList))
732                                             {
733                                               // implicit split of the comment block into two
734                                               // entries. Restart the next block at the start
735                                               // of this command.
736                                               yyextra->parseMore=TRUE;
737 
738                                               // yuk, this is probably not very portable across lex implementations,
739                                               // but we need to know the position in the input buffer where this
740                                               // rule matched.
741                                               // for flex 2.5.33+ we should use YY_CURRENT_BUFFER_LVALUE
742 #if YY_FLEX_MAJOR_VERSION>=2 && (YY_FLEX_MINOR_VERSION>5 || (YY_FLEX_MINOR_VERSION==5 && YY_FLEX_SUBMINOR_VERSION>=33))
743                                               yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf);
744 #else
745                                               yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf);
746 #endif
747                                               yyterminate();
748                                             }
749                                             else if (it->second.handler==0)
750                                             {
751                                               // command without handler, to be processed
752                                               // later by parsedoc.cpp
753                                               addOutput(yyscanner,yytext);
754                                             }
755                                           }
756                                           else // command not relevant
757                                           {
758                                             addOutput(yyscanner,yytext);
759                                           }
760                                         }
761 <Comment>{B}*({CMD}{CMD})"f"[$\[{]      { // escaped formula command
762                                           addOutput(yyscanner,yytext);
763                                         }
764 <Comment>{B}*{CMD}"~"[a-z_A-Z-]*        { // language switch command
765                                           QCString langId = QCString(yytext).stripWhiteSpace().mid(2);
766                                           if (!langId.isEmpty() &&
767                                               qstricmp(Config_getEnumAsString(OUTPUT_LANGUAGE).data(),langId.data())!=0)
768                                           { // enable language specific section
769                                             BEGIN(SkipLang);
770                                           }
771                                         }
772 <Comment>{B}*{CMD}"f{"[^}\n]+"}"("{"?)  { // start of a formula with custom environment
773                                           setOutput(yyscanner,OutputDoc);
774                                           yyextra->formulaText="\\begin";
775                                           yyextra->formulaEnv=QCString(yytext).stripWhiteSpace().mid(2);
776                                           if (yyextra->formulaEnv.at(yyextra->formulaEnv.length()-1)=='{')
777                                           {
778                                             // remove trailing open brace
779                                             yyextra->formulaEnv=yyextra->formulaEnv.left(yyextra->formulaEnv.length()-1);
780                                           }
781                                           yyextra->formulaText+=yyextra->formulaEnv;
782                                           yyextra->formulaNewLines=0;
783                                           BEGIN(ReadFormulaLong);
784                                         }
785 <Comment>{B}*{CMD}"f$"                  { // start of a inline formula
786                                           yyextra->formulaText="$";
787                                           yyextra->formulaNewLines=0;
788                                           BEGIN(ReadFormulaShort);
789                                         }
790 <Comment>{B}*{CMD}"f("                  { // start of a inline formula
791                                           yyextra->formulaText="";
792                                           yyextra->formulaNewLines=0;
793                                           BEGIN(ReadFormulaRound);
794                                         }
795 <Comment>{B}*{CMD}"f["                  { // start of a block formula
796                                           setOutput(yyscanner,OutputDoc);
797                                           yyextra->formulaText="\\[";
798                                           yyextra->formulaNewLines=0;
799                                           BEGIN(ReadFormulaLong);
800                                         }
801 <Comment>{B}*{CMD}"{"                   { // begin of a group
802                                           //yyextra->langParser->handleGroupStartCommand(yyextra->memberGroupHeader);
803                                           yyextra->docGroup.open(yyextra->current,yyextra->fileName,yyextra->lineNr);
804                                         }
805 <Comment>{B}*{CMD}"}"                   { // end of a group
806                                           //yyextra->langParser->handleGroupEndCommand();
807                                           yyextra->docGroup.close(yyextra->current,yyextra->fileName,yyextra->lineNr,TRUE);
808                                           yyextra->docGroup.clearHeader();
809                                           yyextra->parseMore=TRUE;
810                                           yyextra->needNewEntry = TRUE;
811 #if YY_FLEX_MAJOR_VERSION>=2 && (YY_FLEX_MINOR_VERSION>5 || (YY_FLEX_MINOR_VERSION==5 && YY_FLEX_SUBMINOR_VERSION>=33))
812                                           yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) + (int)strlen(yytext);
813 #else
814                                           yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf) + (int)strlen(yytext);
815 #endif
816                                           yyterminate();
817                                         }
818 <Comment>{B}*{CMD}[$@\\&~<>#%]          { // escaped character
819                                           addOutput(yyscanner,yytext);
820                                         }
821 <Comment>[a-z_A-Z]+                     { // normal word
822                                           addOutput(yyscanner,yytext);
823                                         }
824 <Comment>^{B}*"."{Bopt}/\n                { // explicit end autolist: e.g "  ."
825                                             addOutput(yyscanner,yytext);
826                                         }
827 <Comment>^{B}*[1-9][0-9]*"."{B}+        |
828 <Comment>^{B}*[*+]{B}+                  { // start of autolist
829                                           if (!yyextra->markdownSupport)
830                                           {
831                                             REJECT;
832                                           }
833                                           else
834                                           {
835                                             if (yyextra->inContext!=OutputXRef)
836                                             {
837                                               yyextra->briefEndsAtDot=FALSE;
838                                               setOutput(yyscanner,OutputDoc);
839                                             }
840                                             addOutput(yyscanner,yytext);
841                                           }
842                                           }
843 <Comment>^{B}*"-"{B}+                        { // start of autolist
844                                           if (yyextra->inContext!=OutputXRef)
845                                           {
846                                             yyextra->briefEndsAtDot=FALSE;
847                                             setOutput(yyscanner,OutputDoc);
848                                           }
849                                           addOutput(yyscanner,yytext);
850                                         }
851 <Comment>^{B}*([\-:|]{B}*)*("--"|"---")({B}*[\-:|])*{Bopt}/\n { // horizontal line (dashed)
852                                             addOutput(yyscanner,yytext);
853                                         }
854 <Comment>{CMD}"---"                     { // escaped mdash
855                                           addOutput(yyscanner,yytext);
856                                         }
857 <Comment>{CMD}"--"                      { // escaped mdash
858                                           addOutput(yyscanner,yytext);
859                                         }
860 <Comment>"---"                          { // mdash
861                                           addOutput(yyscanner,yyextra->insidePre || yyextra->markdownSupport ? yytext : "&mdash;");
862                                         }
863 <Comment>"--"                           { // ndash
864                                           addOutput(yyscanner,yyextra->insidePre || yyextra->markdownSupport ? yytext : "&ndash;");
865                                         }
866 <Comment>"-#"{B}+                       { // numbered item
867                                           if (yyextra->inContext!=OutputXRef)
868                                           {
869                                             yyextra->briefEndsAtDot=FALSE;
870                                             setOutput(yyscanner,OutputDoc);
871                                           }
872                                           addOutput(yyscanner,yytext);
873                                         }
874 <Comment>("."+)[a-z_A-Z0-9\)]           { // . at start or in the middle of a word, or ellipsis
875                                           addOutput(yyscanner,yytext);
876                                         }
877 <Comment>".\\"[ \t]                     { // . with escaped space.
878                                           addOutput(yyscanner,yytext[0]);
879                                           addOutput(yyscanner,yytext[2]);
880                                         }
881 <Comment>".,"                           { // . with comma such as "e.g.,"
882                                           addOutput(yyscanner,yytext);
883                                         }
884 <Comment>"...\\"[ \t]                   { // ellipsis with escaped space.
885                                           addOutput(yyscanner,"... ");
886                                         }
887 <Comment>"..."/[^\.]                    { // ellipsis
888                                           addOutput(yyscanner,"...");
889                                         }
890 <Comment>".."[\.]?/[^ \t\n]             { // internal ellipsis
891                                           addOutput(yyscanner,yytext);
892                                         }
893 <Comment>(\n|\\ilinebr)({B}*(\n|\\ilinebr))+ { // at least one blank line (or blank line command)
894                                           if (yyextra->inContext==OutputXRef)
895                                           {
896                                             // see bug 613024, we need to put the newlines after ending the XRef section.
897                                             if (!yyextra->insideParBlock) setOutput(yyscanner,OutputDoc);
898                                             yy_size_t i;
899                                             for (i=0;i<(yy_size_t)yyleng;)
900                                             {
901                                               if (yytext[i]=='\n') addOutput(yyscanner,'\n'),i++;
902                                               else if (strcmp(yytext+i,"\\ilinebr")==0) addOutput(yyscanner,"\\ilinebr"),i+=8;
903                                               else i++;
904                                             }
905                                           }
906                                           else if (yyextra->inContext!=OutputBrief)
907                                           {
908                                             yy_size_t i;
909                                             for (i=0;i<(yy_size_t)yyleng;)
910                                             {
911                                               if (yytext[i]=='\n') addOutput(yyscanner,'\n'),i++;
912                                               else if (strcmp(yytext+i,"\\ilinebr")==0) addOutput(yyscanner,"\\ilinebr"),i+=8;
913                                               else i++;
914                                             }
915                                             setOutput(yyscanner,OutputDoc);
916                                           }
917                                           else // yyextra->inContext==OutputBrief
918                                           { // only go to the detailed description if we have
919                                             // found some brief description and not just whitespace
920                                             endBrief(yyscanner,TRUE);
921                                           }
922                                           lineCount(yyscanner);
923                                         }
924 <Comment>"."                            { // potential end of a JavaDoc style comment
925                                           addOutput(yyscanner,*yytext);
926                                           if (yyextra->briefEndsAtDot)
927                                           {
928                                             setOutput(yyscanner,OutputDoc);
929                                             yyextra->briefEndsAtDot=FALSE;
930                                           }
931                                         }
932 <Comment>{DOCNL}                             { // newline
933                                           addOutput(yyscanner,yytext);
934                                           if (*yytext == '\n') yyextra->lineNr++;
935                                         }
936 <Comment>.                              { // catch-all for anything else
937                                           addOutput(yyscanner,*yytext);
938                                         }
939 
940 
941  /* --------------   Rules for handling HTML comments ----------- */
942 
943 <HtmlComment>"--"[!]?">"{B}*            { BEGIN( Comment ); }
944 <HtmlComment>{DOCNL}                    {
945                                           if (*yytext=='\n')
946                                           {
947                                             addOutput(yyscanner,*yytext);
948                                             yyextra->lineNr++;
949                                           }
950                                         }
951 <HtmlComment>[^\\\n\-]+                 { // ignore unimportant characters
952                                         }
953 <HtmlComment>.                          { // ignore every else
954                                         }
955 
956 <CdataSection>"\]\]>"                   {
957                                           BEGIN( Comment );
958                                         }
959 <CdataSection>{DOCNL}                   {
960                                           addOutput(yyscanner,'\n');
961                                           if (*yytext=='\n') yyextra->lineNr++;
962                                         }
963 <CdataSection>[<>&]                     { // the special XML characters for iwhich the CDATA section is especially used
964                                           addOutput(yyscanner,'\\');
965                                           addOutput(yyscanner,*yytext);
966                                         }
967 <CdataSection>[^\\\n\]<>&]+             {
968                                           addOutput(yyscanner,yytext);
969                                         }
970 <CdataSection>.                         {
971                                           addOutput(yyscanner,*yytext);
972                                         }
973 
974  /* --------------   Rules for handling formulas ---------------- */
975 
976 <ReadFormulaShort>{CMD}"f$"             { // end of inline formula
977                                           yyextra->formulaText+="$";
978                                           addOutput(yyscanner," "+addFormula(yyscanner));
979                                           BEGIN(Comment);
980                                         }
981 <ReadFormulaRound>{CMD}"f)"             { // end of inline formula
982                                           addOutput(yyscanner," "+addFormula(yyscanner));
983                                           BEGIN(Comment);
984                                         }
985 <ReadFormulaLong>{CMD}"f]"              { // end of block formula
986                                           yyextra->formulaText+="\\]";
987                                           addOutput(yyscanner," "+addFormula(yyscanner));
988                                           BEGIN(Comment);
989                                         }
990 <ReadFormulaLong>{CMD}"f}"              { // end of custom env formula
991                                           yyextra->formulaText+="\\end";
992                                           yyextra->formulaText+=yyextra->formulaEnv;
993                                           addOutput(yyscanner," "+addFormula(yyscanner));
994                                           BEGIN(Comment);
995                                         }
996 <ReadFormulaLong,ReadFormulaShort,ReadFormulaRound>[^\\@\n]+ { // any non-special character
997                                           yyextra->formulaText+=yytext;
998                                         }
999 <ReadFormulaLong,ReadFormulaShort,ReadFormulaRound>\n    { // new line
1000                                           yyextra->formulaNewLines++;
1001                                           yyextra->formulaText+=*yytext;
1002                                           yyextra->lineNr++;
1003                                         }
1004 <ReadFormulaLong,ReadFormulaShort,ReadFormulaRound>.     { // any other character
1005                                           yyextra->formulaText+=*yytext;
1006                                         }
1007 
1008   /* ------------ handle argument of enum command --------------- */
1009 
1010 <EnumDocArg1>{SCOPEID}                  { // handle argument
1011                                           yyextra->current->name = yytext;
1012                                           BEGIN( Comment );
1013                                         }
1014 <EnumDocArg1>{LC}                       { // line continuation
1015                                           yyextra->lineNr++;
1016                                           addOutput(yyscanner,'\n');
1017                                         }
1018 <EnumDocArg1>{DOCNL}                    { // missing argument
1019                                           warn(yyextra->fileName,yyextra->lineNr,
1020                                                "missing argument after \\enum."
1021                                               );
1022                                           unput_string(yytext,yyleng);
1023                                           //addOutput(yyscanner,'\n');
1024                                           //if (*yytext=='\n') yyextra->lineNr++;
1025                                           BEGIN( Comment );
1026                                         }
1027 <EnumDocArg1>.                          { // ignore other stuff
1028                                         }
1029 
1030   /* ------------ handle argument of namespace command --------------- */
1031 
1032 <NameSpaceDocArg1>{SCOPENAME}           { // handle argument
1033                                           lineCount(yyscanner);
1034                                           yyextra->current->name = substitute(removeRedundantWhiteSpace(QCString(yytext)),QCString("."),QCString("::"));
1035                                           BEGIN( Comment );
1036                                         }
1037 <NameSpaceDocArg1>{LC}                  { // line continuation
1038                                           yyextra->lineNr++;
1039                                           addOutput(yyscanner,'\n');
1040                                         }
1041 <NameSpaceDocArg1>{DOCNL}               { // missing argument
1042                                           warn(yyextra->fileName,yyextra->lineNr,
1043                                                "missing argument after "
1044                                                "\\namespace."
1045                                               );
1046                                           unput_string(yytext,yyleng);
1047                                           //addOutput(yyscanner,'\n');
1048                                           //if (*yytext=='\n') yyextra->lineNr++;
1049                                           BEGIN( Comment );
1050                                         }
1051 <NameSpaceDocArg1>.                     { // ignore other stuff
1052                                         }
1053 
1054   /* ------------ handle argument of package command --------------- */
1055 
1056 <PackageDocArg1>{ID}("."{ID})*          { // handle argument
1057                                           yyextra->current->name = yytext;
1058                                           BEGIN( Comment );
1059                                         }
1060 <PackageDocArg1>{LC}                    { // line continuation
1061                                           yyextra->lineNr++;
1062                                           addOutput(yyscanner,'\n');
1063                                         }
1064 <PackageDocArg1>{DOCNL}                 { // missing argument
1065                                           warn(yyextra->fileName,yyextra->lineNr,
1066                                                "missing argument after "
1067                                                "\\package."
1068                                               );
1069                                           unput_string(yytext,yyleng);
1070                                           //addOutput(yyscanner,'\n');
1071                                           //if (*yytext=='\n') yyextra->lineNr++;
1072                                           BEGIN( Comment );
1073                                         }
1074 <PackageDocArg1>.                       { // ignore other stuff
1075                                         }
1076 
1077   /* ------------ handle argument of concept command --------------- */
1078 
1079 <ConceptDocArg1>{SCOPEID}               { // handle argument
1080                                           yyextra->current->name = yytext;
1081                                           BEGIN( Comment );
1082                                         }
1083 <ConceptDocArg1>{LC}                    { // line continuation
1084                                           yyextra->lineNr++;
1085                                           addOutput(yyscanner,'\n');
1086                                         }
1087 <ConceptDocArg1>{DOCNL}                 { // missing argument
1088                                           warn(yyextra->fileName,yyextra->lineNr,
1089                                                "missing argument after "
1090                                                "\\concept."
1091                                               );
1092                                           unput_string(yytext,yyleng);
1093                                           BEGIN( Comment );
1094                                         }
1095 <ConceptDocArg1>.                       { // ignore other stuff
1096                                         }
1097 
1098 
1099   /* ------ handle argument of class/struct/union command --------------- */
1100 
1101 <ClassDocArg1>{SCOPENAME}{TMPLSPEC}     {
1102                                           lineCount(yyscanner);
1103                                           yyextra->current->name = substitute(removeRedundantWhiteSpace(QCString(yytext)),".","::");
1104                                           BEGIN( ClassDocArg2 );
1105                                         }
1106 <ClassDocArg1>{SCOPENAME}               { // first argument
1107                                           lineCount(yyscanner);
1108                                           yyextra->current->name = substitute(QCString(yytext),".","::");
1109                                           if (yyextra->current->section==Entry::PROTOCOLDOC_SEC)
1110                                           {
1111                                             yyextra->current->name+="-p";
1112                                           }
1113                                           // prepend outer scope name
1114                                           BEGIN( ClassDocArg2 );
1115                                         }
1116 <CategoryDocArg1>{SCOPENAME}{B}*"("[^\)]+")" {
1117                                           lineCount(yyscanner);
1118                                           yyextra->current->name = substitute(QCString(yytext),".","::");
1119                                           BEGIN( ClassDocArg2 );
1120                                         }
1121 <ClassDocArg1,CategoryDocArg1>{LC}      { // line continuation
1122                                           yyextra->lineNr++;
1123                                           addOutput(yyscanner,'\n');
1124                                         }
1125 <ClassDocArg1,CategoryDocArg1>{DOCNL}   {
1126                                           warn(yyextra->fileName,yyextra->lineNr,
1127                                                "missing argument after "
1128                                                "'\\%s'.",qPrint(yyextra->currentCmd)
1129                                               );
1130                                           //addOutput(yyscanner,'\n');
1131                                           //if (*yytext=='\n') yyextra->lineNr++;
1132                                           unput_string(yytext,yyleng);
1133                                           BEGIN( Comment );
1134                                         }
1135 <ClassDocArg1,CategoryDocArg1>.         { // ignore other stuff
1136                                         }
1137 
1138 <ClassDocArg2>{DOCNL}                   {
1139                                           //addOutput(yyscanner,'\n');
1140                                           //if (*yytext=='\n') yyextra->lineNr++;
1141                                           unput_string(yytext,yyleng);
1142                                           BEGIN( Comment );
1143                                         }
1144 <ClassDocArg2>{FILE}|"<>"               { // second argument; include file
1145                                           yyextra->current->includeFile = yytext;
1146                                           BEGIN( ClassDocArg3 );
1147                                         }
1148 <ClassDocArg2>{LC}                      { // line continuation
1149                                           yyextra->lineNr++;
1150                                           addOutput(yyscanner,'\n');
1151                                         }
1152 <ClassDocArg2>.                         { // ignore other stuff
1153                                         }
1154 
1155 <ClassDocArg3>[<"]?{FILE}?[">]?         { // third argument; include file name
1156                                           yyextra->current->includeName = yytext;
1157                                           BEGIN( Comment );
1158                                         }
1159 <ClassDocArg3>{LC}                      { // line continuation
1160                                           yyextra->lineNr++;
1161                                           addOutput(yyscanner,'\n');
1162                                         }
1163 <ClassDocArg3>{DOCNL}                   {
1164                                           //if (*yytext=='\n') yyextra->lineNr++;
1165                                           unput_string(yytext,yyleng);
1166                                           BEGIN( Comment );
1167                                         }
1168 <ClassDocArg3>.                         { // ignore other stuff
1169                                         }
1170 
1171   /* --------- handle arguments of {def,add,weak}group commands --------- */
1172 
1173 <GroupDocArg1>{LABELID}(".html"?)       { // group name
1174                                            yyextra->current->name = yytext;
1175                                           //lastDefGroup.groupname = yytext;
1176                                           //lastDefGroup.pri = yyextra->current->groupingPri();
1177                                           // the .html stuff is for Qt compatibility
1178                                           if (yyextra->current->name.right(5)==".html")
1179                                           {
1180                                             yyextra->current->name=yyextra->current->name.left(yyextra->current->name.length()-5);
1181                                           }
1182                                           yyextra->current->type.resize(0);
1183                                           BEGIN(GroupDocArg2);
1184                                         }
1185 <GroupDocArg1>"\\"{B}*"\n"              { // line continuation
1186                                           yyextra->lineNr++;
1187                                           addOutput(yyscanner,'\n');
1188                                         }
1189 <GroupDocArg1>{DOCNL}                   { // missing argument!
1190                                           warn(yyextra->fileName,yyextra->lineNr,
1191                                                "missing group name after %s",
1192                                                yyextra->current->groupDocCmd()
1193                                               );
1194                                           //addOutput(yyscanner,'\n');
1195                                           //if (*yytext=='\n') yyextra->lineNr++;
1196                                           unput_string(yytext,yyleng);
1197                                           BEGIN( Comment );
1198                                         }
1199 <GroupDocArg1>.                         { // ignore other stuff
1200                                         }
1201 <GroupDocArg2>"\\"{B}*"\n"              { // line continuation
1202                                           yyextra->lineNr++;
1203                                           addOutput(yyscanner,'\n');
1204                                         }
1205 <GroupDocArg2>[^\n\\]+                  { // title (stored in type)
1206                                           yyextra->current->type += yytext;
1207                                           yyextra->current->type = yyextra->current->type.stripWhiteSpace();
1208                                         }
1209 <GroupDocArg2>{DOCNL}                   {
1210                                           if ( yyextra->current->groupDocType==Entry::GROUPDOC_NORMAL &&
1211                                                yyextra->current->type.isEmpty()
1212                                              ) // defgroup requires second argument
1213                                           {
1214                                               warn(yyextra->fileName,yyextra->lineNr,
1215                                                  "missing title after "
1216                                                  "\\defgroup %s", qPrint(yyextra->current->name)
1217                                                 );
1218                                           }
1219                                           unput_string(yytext,yyleng);
1220                                           //if (*yytext=='\n') yyextra->lineNr++;
1221                                           //addOutput(yyscanner,'\n');
1222                                           BEGIN( Comment );
1223                                         }
1224 <GroupDocArg2>.                         { // title (stored in type)
1225                                           yyextra->current->type += yytext;
1226                                           yyextra->current->type = yyextra->current->type.stripWhiteSpace();
1227                                         }
1228 
1229   /* --------- handle arguments of page/mainpage command ------------------- */
1230 
1231 <PageDocArg1>{FILE}                     { // first argument; page name
1232                                           yyextra->current->name = stripQuotes(yytext);
1233                                           yyextra->current->args = "";
1234                                           BEGIN( PageDocArg2 );
1235                                         }
1236 <PageDocArg1>{LC}                       { yyextra->lineNr++;
1237                                           addOutput(yyscanner,'\n');
1238                                         }
1239 <PageDocArg1>{DOCNL}                    {
1240                                             warn(yyextra->fileName,yyextra->lineNr,
1241                                                "missing argument after "
1242                                                "\\page."
1243                                               );
1244                                           unput_string(yytext,yyleng);
1245                                           //if (*yytext=='\n') yyextra->lineNr++;
1246                                           //addOutput(yyscanner,'\n');
1247                                           BEGIN( Comment );
1248                                         }
1249 <PageDocArg1>.                          { // ignore other stuff
1250                                         }
1251 <PageDocArg2>{DOCNL}                    { // second argument; page title
1252                                           unput_string(yytext,yyleng);
1253                                           //if (*yytext=='\n') yyextra->lineNr++;
1254                                           //addOutput(yyscanner,'\n');
1255                                           BEGIN( Comment );
1256                                         }
1257 <PageDocArg2>{CMD}[<>]                  {
1258                                           // bug 748927
1259                                           QCString tmp(yytext);
1260                                           tmp = substitute(substitute(tmp,"@<","&lt;"),"@>","&gt;");
1261                                           tmp = substitute(substitute(tmp,"\\<","&lt;"),"\\>","&gt;");
1262                                           yyextra->current->args += tmp;
1263                                         }
1264 <PageDocArg2>.                          {
1265                                           yyextra->current->args += yytext;
1266                                         }
1267   /* --------- handle arguments of the param command ------------ */
1268 <ParamArg1>{ID}/{B}*","                 {
1269                                           addOutput(yyscanner,yytext);
1270                                         }
1271 <ParamArg1>","                          {
1272                                           addOutput(yyscanner," , ");
1273                                         }
1274 <ParamArg1>{DOCNL}                      {
1275                                           if (*yytext=='\n') yyextra->lineNr++;
1276                                           addOutput(yyscanner," ");
1277                                         }
1278 <ParamArg1>{ID}                         {
1279                                           addOutput(yyscanner,yytext);
1280                                           BEGIN( Comment );
1281                                         }
1282 <ParamArg1>.                            {
1283                                           unput(yytext[0]);
1284                                           BEGIN( Comment );
1285                                         }
1286 
1287   /* --------- handle arguments of the file/dir/example command ------------ */
1288 
1289 <FileDocArg1>{DOCNL}                    { // no file name specified
1290                                           unput_string(yytext,yyleng);
1291                                           //if (*yytext=='\n') yyextra->lineNr++;
1292                                           //addOutput(yyscanner,'\n');
1293                                           BEGIN( Comment );
1294                                         }
1295 <FileDocArg1>{FILE}                     { // first argument; name
1296                                           yyextra->current->name = stripQuotes(yytext);
1297                                           BEGIN( Comment );
1298                                         }
1299 <FileDocArg1>{LC}                       { yyextra->lineNr++;
1300                                           addOutput(yyscanner,'\n');
1301                                         }
1302 <FileDocArg1>.                          { // ignore other stuff
1303                                         }
1304 
1305   /* --------- handle arguments of the xrefitem command ------------ */
1306 
1307 <XRefItemParam1>{LABELID}               { // first argument
1308                                           yyextra->newXRefItemKey=yytext;
1309                                           setOutput(yyscanner,OutputXRef);
1310                                           BEGIN(XRefItemParam2);
1311                                         }
1312 <XRefItemParam1>{LC}                    { // line continuation
1313                                           yyextra->lineNr++;
1314                                           addOutput(yyscanner,'\n');
1315                                         }
1316 <XRefItemParam1>{DOCNL}                 { // missing arguments
1317                                           warn(yyextra->fileName,yyextra->lineNr,
1318                                                "Missing first argument of \\xrefitem"
1319                                               );
1320                                           if (*yytext=='\n') yyextra->lineNr++;
1321                                           addOutput(yyscanner,'\n');
1322                                           yyextra->inContext = OutputDoc;
1323                                           BEGIN( Comment );
1324                                         }
1325 <XRefItemParam1>.                       { // ignore other stuff
1326                                         }
1327 
1328 <XRefItemParam2>"\""[^\n\"]*"\""        { // second argument
1329                                           yyextra->xrefItemTitle = stripQuotes(yytext);
1330                                           BEGIN(XRefItemParam3);
1331                                         }
1332 <XRefItemParam2>{LC}                    { // line continuation
1333                                           yyextra->lineNr++;
1334                                           addOutput(yyscanner,'\n');
1335                                         }
1336 <XRefItemParam2>{DOCNL}                 { // missing argument
1337                                           warn(yyextra->fileName,yyextra->lineNr,
1338                                               "Missing second argument of \\xrefitem"
1339                                               );
1340                                           if (*yytext=='\n') yyextra->lineNr++;
1341                                           addOutput(yyscanner,'\n');
1342                                           yyextra->inContext = OutputDoc;
1343                                           BEGIN( Comment );
1344                                         }
1345 <XRefItemParam2>.                       { // ignore other stuff
1346                                         }
1347 
1348 <XRefItemParam3>"\""[^\n\"]*"\""        { // third argument
1349                                           yyextra->xrefListTitle = stripQuotes(yytext);
1350                                           yyextra->xrefKind = XRef_Item;
1351                                           BEGIN( Comment );
1352                                         }
1353 <XRefItemParam2,XRefItemParam3>{LC}     { // line continuation
1354                                           yyextra->lineNr++;
1355                                           addOutput(yyscanner,'\n');
1356                                         }
1357 <XRefItemParam3>{DOCNL}                 { // missing argument
1358                                           warn(yyextra->fileName,yyextra->lineNr,
1359                                               "Missing third argument of \\xrefitem"
1360                                               );
1361                                           if (*yytext=='\n') yyextra->lineNr++;
1362                                           addOutput(yyscanner,'\n');
1363                                           yyextra->inContext = OutputDoc;
1364                                           BEGIN( Comment );
1365                                         }
1366 <XRefItemParam3>.                       { // ignore other stuff
1367                                         }
1368 
1369 
1370   /* ----- handle arguments of the relates(also)/memberof command ------- */
1371 
1372 <RelatesParam1>({ID}("::"|"."))*{ID}    { // argument
1373                                           yyextra->current->relates = yytext;
1374                                           //if (yyextra->current->mGrpId!=DOX_NOGROUP)
1375                                           //{
1376                                           //  memberGroupRelates = yytext;
1377                                           //}
1378                                           BEGIN( Comment );
1379                                         }
1380 <RelatesParam1>{LC}                     { // line continuation
1381                                           yyextra->lineNr++;
1382                                           addOutput(yyscanner,'\n');
1383                                         }
1384 <RelatesParam1>{DOCNL}                  { // missing argument
1385                                           warn(yyextra->fileName,yyextra->lineNr,
1386                                               "Missing argument of '\\%s' command",qPrint(yyextra->currentCmd)
1387                                               );
1388                                           unput_string(yytext,yyleng);
1389                                           //if (*yytext=='\n') yyextra->lineNr++;
1390                                           //addOutput(yyscanner,'\n');
1391                                           BEGIN( Comment );
1392                                         }
1393 <RelatesParam1>.                        { // ignore other stuff
1394                                         }
1395 
1396 
1397   /* ----- handle arguments of the relates(also)/addindex commands ----- */
1398 
1399 <LineParam>{DOCNL}                      { // end of argument
1400                                           //if (*yytext=='\n') yyextra->lineNr++;
1401                                           //addOutput(yyscanner,'\n');
1402                                           unput_string(yytext,yyleng);
1403                                           BEGIN( Comment );
1404                                         }
1405 <LineParam>{LC}                         { // line continuation
1406                                           yyextra->lineNr++;
1407                                           addOutput(yyscanner,'\n');
1408                                         }
1409 <LineParam>.                            { // ignore other stuff
1410                                           addOutput(yyscanner,*yytext);
1411                                         }
1412 
1413   /* ----- handle arguments of the section/subsection/.. commands ------- */
1414 
1415 <SectionLabel>{LABELID}                 { // first argument
1416                                           yyextra->sectionLabel=yytext;
1417                                           addOutput(yyscanner,yytext);
1418                                           yyextra->sectionTitle.resize(0);
1419                                           BEGIN(SectionTitle);
1420                                         }
1421 <SectionLabel>{DOCNL}                   { // missing argument
1422                                           warn(yyextra->fileName,yyextra->lineNr,
1423                                               "\\section command has no label"
1424                                               );
1425                                           if (*yytext=='\n') yyextra->lineNr++;
1426                                           addOutput(yyscanner,'\n');
1427                                           BEGIN( Comment );
1428                                         }
1429 <SectionLabel>.                         { // invalid character for section label
1430                                           warn(yyextra->fileName,yyextra->lineNr,
1431                                               "Invalid or missing section label"
1432                                               );
1433                                           BEGIN(Comment);
1434                                         }
1435 <SectionTitle>{STAopt}/"\n"             { // end of section title
1436                                           addSection(yyscanner);
1437                                           addOutput(yyscanner,yytext);
1438                                           BEGIN( Comment );
1439                                         }
1440 <SectionTitle>{STopt}/"\\ilinebr"       { // end of section title
1441                                           addSection(yyscanner);
1442                                           addOutput(yyscanner,yytext);
1443                                           BEGIN( Comment );
1444                                         }
1445 <SectionTitle>{LC}                      { // line continuation
1446                                           yyextra->lineNr++;
1447                                           addOutput(yyscanner,'\n');
1448                                         }
1449 <SectionTitle>[^\n@\\]*                 { // any character without special meaning
1450                                           yyextra->sectionTitle+=yytext;
1451                                           addOutput(yyscanner,yytext);
1452                                         }
1453 <SectionTitle>({CMD}{CMD}){ID}          { // unescape escaped command
1454                                           yyextra->sectionTitle+=&yytext[1];
1455                                           addOutput(yyscanner,yytext);
1456                                         }
1457 <SectionTitle>{CMD}[$@\\&~<>#%]         { // unescape escaped character
1458                                           yyextra->sectionTitle+=yytext[1];
1459                                           addOutput(yyscanner,yytext);
1460                                         }
1461 <SectionTitle>.                         { // anything else
1462                                           yyextra->sectionTitle+=yytext;
1463                                           addOutput(yyscanner,*yytext);
1464                                         }
1465 
1466   /* ----- handle arguments of the subpage command ------- */
1467 
1468 <SubpageLabel>{LABELID}                 { // first argument
1469                                           addOutput(yyscanner,yytext);
1470                                           // we add subpage labels as a kind of "inheritance" relation to prevent
1471                                           // needing to add another list to the Entry class.
1472                                           yyextra->current->extends.push_back(BaseInfo(QCString(yytext),Public,Normal));
1473                                           BEGIN(SubpageTitle);
1474                                         }
1475 <SubpageLabel>{DOCNL}                   { // missing argument
1476                                           warn(yyextra->fileName,yyextra->lineNr,
1477                                               "\\subpage command has no label"
1478                                               );
1479                                           if (*yytext=='\n') yyextra->lineNr++;
1480                                           addOutput(yyscanner,'\n');
1481                                           BEGIN( Comment );
1482                                         }
1483 <SubpageTitle>{DOCNL}                   { // no title, end command
1484                                           addOutput(yyscanner,yytext);
1485                                           BEGIN( Comment );
1486                                         }
1487 <SubpageTitle>[ \t]*"\""[^\"\n]*"\""    { // add title, end of command
1488                                           addOutput(yyscanner,yytext);
1489                                           BEGIN( Comment );
1490                                         }
1491 <SubpageTitle>.                         { // no title, end of command
1492                                           unput(*yytext);
1493                                           BEGIN( Comment );
1494                                         }
1495 
1496   /* ----- handle arguments of the anchor command ------- */
1497 
1498 <AnchorLabel>{LABELID}                  { // found argument
1499                                           addAnchor(yyscanner,QCString(yytext));
1500                                           addOutput(yyscanner,yytext);
1501                                           BEGIN( Comment );
1502                                         }
1503 <AnchorLabel>{DOCNL}                    { // missing argument
1504                                           warn(yyextra->fileName,yyextra->lineNr,
1505                                               "\\anchor command has no label"
1506                                               );
1507                                           if (*yytext=='\n') yyextra->lineNr++;
1508                                           addOutput(yyscanner,'\n');
1509                                           BEGIN( Comment );
1510                                         }
1511 <AnchorLabel>.                          { // invalid character for anchor label
1512                                           warn(yyextra->fileName,yyextra->lineNr,
1513                                               "Invalid or missing anchor label"
1514                                               );
1515                                           BEGIN(Comment);
1516                                         }
1517 
1518 
1519   /* ----- handle arguments of the preformatted block commands ------- */
1520 
1521 <FormatBlock>{CMD}("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"endmsc")/{NW} { // possible ends
1522                                           addOutput(yyscanner,yytext);
1523                                           if (&yytext[4]==yyextra->blockName) // found end of the block
1524                                           {
1525                                               BEGIN(Comment);
1526                                           }
1527                                         }
1528 <FormatBlock>{CMD}"enduml"              {
1529                                           addOutput(yyscanner,yytext);
1530                                           if (yyextra->blockName=="startuml") // found end of the block
1531                                           {
1532                                               BEGIN(Comment);
1533                                           }
1534                                         }
1535 <FormatBlock>[^ \@\*\/\\\n]*            { // some word
1536                                           addOutput(yyscanner,yytext);
1537                                         }
1538 <FormatBlock>{DOCNL}                    { // new line
1539                                           if (*yytext=='\n') yyextra->lineNr++;
1540                                           addOutput(yyscanner,'\n');
1541                                         }
1542 <FormatBlock>{CCS}                       { // start of a C-comment
1543                                           if (!(yyextra->blockName=="code" || yyextra->blockName=="verbatim" || yyextra->blockName=="iliteral")) yyextra->commentCount++;
1544                                           addOutput(yyscanner,yytext);
1545                                         }
1546 <FormatBlock>{CCE}                       { // end of a C-comment
1547                                           addOutput(yyscanner,yytext);
1548                                           if (!(yyextra->blockName=="code" || yyextra->blockName=="verbatim" || yyextra->blockName=="iliteral"))
1549                                           {
1550                                             yyextra->commentCount--;
1551                                             if (yyextra->commentCount<0)
1552                                             {
1553                                               QCString endTag = "end"+yyextra->blockName;
1554                                               if (yyextra->blockName=="startuml") endTag="enduml";
1555                                               warn(yyextra->fileName,yyextra->lineNr,
1556                                                  "found */ without matching /* while inside a \\%s block! Perhaps a missing \\%s?\n",qPrint(yyextra->blockName),qPrint(endTag));
1557                                             }
1558                                           }
1559                                         }
1560 <FormatBlock>.                          {
1561                                           addOutput(yyscanner,*yytext);
1562                                         }
1563 <FormatBlock><<EOF>>                    {
1564                                           QCString endTag = "end"+yyextra->blockName;
1565                                           if (yyextra->blockName=="startuml") endTag="enduml";
1566                                           warn(yyextra->fileName,yyextra->lineNr,
1567                                             "reached end of comment while inside a \\%s block; check for missing \\%s tag!",
1568                                             qPrint(yyextra->blockName),qPrint(endTag)
1569                                           );
1570                                           yyterminate();
1571                                         }
1572 
1573   /* ----- handle arguments of if/ifnot commands ------- */
1574 
1575 <GuardParam>{B}*"("                     {
1576                                           yyextra->guardExpr=yytext;
1577                                           yyextra->roundCount=1;
1578                                           BEGIN(GuardExpr);
1579                                         }
1580 <GuardExpr>[^()]*                       {
1581                                           yyextra->guardExpr+=yytext;
1582                                           lineCount(yyscanner);
1583                                         }
1584 <GuardExpr>"("                          {
1585                                           yyextra->guardExpr+=yytext;
1586                                           yyextra->roundCount++;
1587                                         }
1588 <GuardExpr>")"                          {
1589                                           yyextra->guardExpr+=yytext;
1590                                           yyextra->roundCount--;
1591                                           if (yyextra->roundCount==0)
1592                                           {
1593                                             handleGuard(yyscanner,yyextra->guardExpr);
1594                                           }
1595                                         }
1596 <GuardExpr>\n                           {
1597                                           warn(yyextra->fileName,yyextra->lineNr,
1598                                                 "invalid expression '%s' for yyextra->guards",qPrint(yyextra->guardExpr));
1599                                           unput(*yytext);
1600                                           BEGIN(GuardParam);
1601                                         }
1602 <GuardParam>{B}*[a-z_A-Z0-9.\-]+        { // parameter of if/ifnot yyextra->guards
1603                                           handleGuard(yyscanner,QCString(yytext));
1604                                         }
1605 <GuardParam>{DOCNL}                     { // end of argument
1606                                           if (*yytext=='\n') yyextra->lineNr++;
1607                                           //next line is commented out due to bug620924
1608                                           //addOutput(yyscanner,'\n');
1609                                           addIline(yyscanner,yyextra->lineNr);
1610                                           BEGIN( Comment );
1611                                         }
1612 <GuardParam>{LC}                        { // line continuation
1613                                           yyextra->lineNr++;
1614                                           addOutput(yyscanner,'\n');
1615                                         }
1616 <GuardParam>.                           { // ignore other stuff
1617                                           addOutput(yyscanner,*yytext);
1618                                         }
1619 <GuardParamEnd>{B}*{DOCNL}              {
1620                                           lineCount(yyscanner);
1621                                           yyextra->spaceBeforeIf.resize(0);
1622                                           addIline(yyscanner,yyextra->lineNr);
1623                                           BEGIN(Comment);
1624                                         }
1625 <GuardParamEnd>{B}*                     {
1626                                           if (!yyextra->spaceBeforeIf.isEmpty()) // needed for 665313 in combination with bug620924
1627                                           {
1628                                             addOutput(yyscanner,yyextra->spaceBeforeIf);
1629                                           }
1630                                           yyextra->spaceBeforeIf.resize(0);
1631                                           addIline(yyscanner,yyextra->lineNr);
1632                                           BEGIN(Comment);
1633                                         }
1634 <GuardParamEnd>.                        {
1635                                           unput(*yytext);
1636                                           addIline(yyscanner,yyextra->lineNr);
1637                                           BEGIN(Comment);
1638                                         }
1639 
1640   /* ----- handle skipping of conditional sections ------- */
1641 
1642 <SkipGuardedSection>{CMD}"ifnot"/{NW}   {
1643                                           yyextra->guardType = Guard_IfNot;
1644                                           BEGIN( GuardParam );
1645                                         }
1646 <SkipGuardedSection>{CMD}"if"/{NW}      {
1647                                           yyextra->guardType = Guard_If;
1648                                           BEGIN( GuardParam );
1649                                         }
1650 <SkipGuardedSection>{CMD}"endif"/{NW}   {
1651                                           if (yyextra->guards.empty())
1652                                           {
1653                                             warn(yyextra->fileName,yyextra->lineNr,
1654                                                 "found \\endif without matching start command");
1655                                           }
1656                                           else
1657                                           {
1658                                             GuardedSection s = yyextra->guards.top();
1659                                             yyextra->guards.pop();
1660                                             bool parentVisible = s.parentVisible();
1661                                             if (parentVisible)
1662                                             {
1663                                               yyextra->enabledSectionFound=TRUE;
1664                                               BEGIN( GuardParamEnd );
1665                                             }
1666                                           }
1667                                         }
1668 <SkipGuardedSection>{CMD}"else"/{NW}    {
1669                                           if (yyextra->guards.empty())
1670                                           {
1671                                             warn(yyextra->fileName,yyextra->lineNr,
1672                                                 "found \\else without matching start command");
1673                                           }
1674                                           else
1675                                           {
1676                                             if (!yyextra->enabledSectionFound && yyextra->guards.top().parentVisible())
1677                                             {
1678                                               yyextra->guards.pop();
1679                                               yyextra->guards.push(GuardedSection(TRUE,TRUE));
1680                                               yyextra->enabledSectionFound=TRUE;
1681                                               BEGIN( GuardParamEnd );
1682                                             }
1683                                           }
1684                                         }
1685 <SkipGuardedSection>{CMD}"elseif"/{NW}  {
1686                                           if (yyextra->guards.empty())
1687                                           {
1688                                             warn(yyextra->fileName,yyextra->lineNr,
1689                                                 "found \\elseif without matching start command");
1690                                           }
1691                                           else
1692                                           {
1693                                             if (!yyextra->enabledSectionFound && yyextra->guards.top().parentVisible())
1694                                             {
1695                                               yyextra->guardType=Guard_If;
1696                                               yyextra->guards.pop();
1697                                               BEGIN( GuardParam );
1698                                             }
1699                                           }
1700                                         }
1701 <SkipGuardedSection>{DOCNL}             { // skip line
1702                                           if (*yytext=='\n') yyextra->lineNr++;
1703                                           //addOutput(yyscanner,'\n');
1704                                         }
1705 <SkipGuardedSection>[^ \\@\n]+          { // skip non-special characters
1706                                         }
1707 <SkipGuardedSection>.                   { // any other character
1708                                         }
1709 
1710 
1711   /* ----- handle skipping of internal section ------- */
1712 
1713 <SkipInternal>{DOCNL}                   { // skip line
1714                                           if (*yytext=='\n') yyextra->lineNr++;
1715                                           addOutput(yyscanner,'\n');
1716                                         }
1717 <SkipInternal>[@\\]"if"/[ \t]           {
1718                                           yyextra->condCount++;
1719                                           }
1720 <SkipInternal>[@\\]"ifnot"/[ \t]        {
1721                                           yyextra->condCount++;
1722                                         }
1723 <SkipInternal>[@\\]/"endif"             {
1724                                           yyextra->condCount--;
1725                                           if (yyextra->condCount<0) // handle conditional section around of \internal, see bug607743
1726                                           {
1727                                             unput('\\');
1728                                             BEGIN(Comment);
1729                                           }
1730                                         }
1731 <SkipInternal>[@\\]/"section"[ \t]      {
1732                                           if (yyextra->sectionLevel>0)
1733                                           {
1734                                             unput('\\');
1735                                             BEGIN(Comment);
1736                                           }
1737                                         }
1738 <SkipInternal>[@\\]/"subsection"[ \t]   {
1739                                           if (yyextra->sectionLevel>1)
1740                                           {
1741                                             unput('\\');
1742                                             BEGIN(Comment);
1743                                           }
1744                                         }
1745 <SkipInternal>[@\\]/"subsubsection"[ \t] {
1746                                           if (yyextra->sectionLevel>2)
1747                                           {
1748                                             unput('\\');
1749                                             BEGIN(Comment);
1750                                           }
1751                                         }
1752 <SkipInternal>[@\\]/"paragraph"[ \t]    {
1753                                           if (yyextra->sectionLevel>3)
1754                                           {
1755                                             unput('\\');
1756                                             BEGIN(Comment);
1757                                           }
1758                                         }
1759 <SkipInternal>[@\\]"endinternal"[ \t]*  {
1760                                           BEGIN(Comment);
1761                                         }
1762 <SkipInternal>[^ \\@\n]+                { // skip non-special characters
1763                                         }
1764 <SkipInternal>.                         { // any other character
1765                                         }
1766 
1767 
1768   /* ----- handle argument of name command ------- */
1769 
1770 <NameParam>{DOCNL}                      { // end of argument
1771                                           //if (*yytext=='\n') yyextra->lineNr++;
1772                                           //addOutput(yyscanner,'\n');
1773                                           unput_string(yytext,yyleng);
1774                                           BEGIN( Comment );
1775                                         }
1776 <NameParam>{LC}                         { // line continuation
1777                                           yyextra->lineNr++;
1778                                           addOutput(yyscanner,'\n');
1779                                           yyextra->docGroup.appendHeader(' ');
1780                                         }
1781 <NameParam>.                            { // ignore other stuff
1782                                           yyextra->docGroup.appendHeader(*yytext);
1783                                           yyextra->current->name+=*yytext;
1784                                         }
1785 
1786   /* ----- handle argument of noop command ------- */
1787 <Noop>{DOCNL}                           { // end of argument
1788                                           if (*yytext=='\n') yyextra->lineNr++;
1789                                           addOutput(yyscanner,'\n');
1790                                           BEGIN( Comment );
1791                                         }
1792 <Noop>.                                 { // ignore other stuff
1793                                         }
1794   /* ----- handle argument of raisewarning command ------- */
1795 <RaiseWarning>{DOCNL}                   { // end of argument
1796                                           warn_doc_error(yyextra->fileName,yyextra->lineNr,
1797                                                          "%s",qPrint(yyextra->raiseWarning));
1798                                           yyextra->raiseWarning = "";
1799                                           if (*yytext=='\n') yyextra->lineNr++;
1800                                           addOutput(yyscanner,'\n');
1801                                           BEGIN( Comment );
1802                                         }
1803 <RaiseWarning>.                         { // ignore other stuff
1804                                           yyextra->raiseWarning += yytext;
1805                                         }
1806   /* ----- handle argument of ingroup command ------- */
1807 
1808 <InGroupParam>{LABELID}                 { // group id
1809                                           yyextra->current->groups.push_back(
1810                                              Grouping(QCString(yytext), Grouping::GROUPING_INGROUP)
1811                                           );
1812                                           yyextra->inGroupParamFound=TRUE;
1813                                         }
1814 <InGroupParam>{DOCNL}                   { // missing argument
1815                                           if (!yyextra->inGroupParamFound)
1816                                           {
1817                                              warn(yyextra->fileName,yyextra->lineNr,
1818                                                 "Missing group name for \\ingroup command"
1819                                                 );
1820                                           }
1821                                           //if (*yytext=='\n') yyextra->lineNr++;
1822                                           //addOutput(yyscanner,'\n');
1823                                           unput_string(yytext,yyleng);
1824                                           BEGIN( Comment );
1825                                         }
1826 <InGroupParam>{LC}                      { // line continuation
1827                                           yyextra->lineNr++;
1828                                           addOutput(yyscanner,'\n');
1829                                         }
1830 <InGroupParam>.                         { // ignore other stuff
1831                                           addOutput(yyscanner,*yytext);
1832                                         }
1833 
1834   /* ----- handle argument of fn command ------- */
1835 
1836 <FnParam>{DOCNL}                        { // end of argument
1837                                           if (yyextra->braceCount==0)
1838                                           {
1839                                             //if (*yytext=='\n') yyextra->lineNr++;
1840                                             //addOutput(yyscanner,'\n');
1841                                             unput_string(yytext,yyleng);
1842                                             yyextra->langParser->parsePrototype(yyextra->functionProto);
1843                                             BEGIN( Comment );
1844                                           }
1845                                         }
1846 <FnParam>{LC}                           { // line continuation
1847                                           yyextra->lineNr++;
1848                                           yyextra->functionProto+=' ';
1849                                         }
1850 <FnParam>[^@\\\n()]+                    { // non-special characters
1851                                           yyextra->functionProto+=yytext;
1852                                         }
1853 <FnParam>"("                            {
1854                                           yyextra->functionProto+=yytext;
1855                                           yyextra->braceCount++;
1856                                         }
1857 <FnParam>")"                            {
1858                                           yyextra->functionProto+=yytext;
1859                                           yyextra->braceCount--;
1860                                         }
1861 <FnParam>.                              { // add other stuff
1862                                           yyextra->functionProto+=*yytext;
1863                                         }
1864 
1865 
1866   /* ----- handle argument of overload command ------- */
1867 
1868 
1869 <OverloadParam>{DOCNL}                  { // end of argument
1870                                           if (*yytext=='\n') yyextra->lineNr++;
1871                                           if (yyextra->functionProto.stripWhiteSpace().isEmpty())
1872                                           { // plain overload command
1873                                             addOutput(yyscanner,getOverloadDocs());
1874                                             addOutput(yyscanner,'\n');
1875                                           }
1876                                           else // overload declaration
1877                                           {
1878                                             makeStructuralIndicator(yyscanner,Entry::OVERLOADDOC_SEC);
1879                                             yyextra->langParser->parsePrototype(yyextra->functionProto);
1880                                           }
1881                                           BEGIN( Comment );
1882                                         }
1883 <OverloadParam>{LC}                     { // line continuation
1884                                           yyextra->lineNr++;
1885                                           yyextra->functionProto+=' ';
1886                                         }
1887 <OverloadParam>.                        { // add other stuff
1888                                           yyextra->functionProto+=*yytext;
1889                                         }
1890 
1891   /* ----- handle argument of inherit command ------- */
1892 
1893 <InheritParam>({ID}("::"|"."))*{ID}     { // found argument
1894                                           yyextra->current->extends.push_back(
1895                                             BaseInfo(removeRedundantWhiteSpace(QCString(yytext)),Public,Normal)
1896                                           );
1897                                           BEGIN( Comment );
1898                                         }
1899 <InheritParam>{DOCNL}                   { // missing argument
1900                                           warn(yyextra->fileName,yyextra->lineNr,
1901                                               "\\inherit command has no argument"
1902                                               );
1903                                           if (*yytext=='\n') yyextra->lineNr++;
1904                                           addOutput(yyscanner,'\n');
1905                                           BEGIN( Comment );
1906                                         }
1907 <InheritParam>.                         { // invalid character for anchor label
1908                                           warn(yyextra->fileName,yyextra->lineNr,
1909                                               "Invalid or missing name for \\inherit command"
1910                                               );
1911                                           BEGIN(Comment);
1912                                         }
1913 
1914   /* ----- handle argument of extends and implements commands ------- */
1915 
1916 <ExtendsParam>({ID}("::"|"."))*{ID}     { // found argument
1917                                           yyextra->current->extends.push_back(
1918                                             BaseInfo(removeRedundantWhiteSpace(QCString(yytext)),Public,Normal)
1919                                           );
1920                                           BEGIN( Comment );
1921                                         }
1922 <ExtendsParam>{DOCNL}                   { // missing argument
1923                                           warn(yyextra->fileName,yyextra->lineNr,
1924                                               "'\\%s' command has no argument",qPrint(yyextra->currentCmd)
1925                                               );
1926                                           //if (*yytext=='\n') yyextra->lineNr++;
1927                                           //addOutput(yyscanner,'\n');
1928                                           unput_string(yytext,yyleng);
1929                                           BEGIN( Comment );
1930                                         }
1931 <ExtendsParam>.                         { // ignore other stuff
1932                                         }
1933 
1934   /* ----- handle language specific sections ------- */
1935 
1936 <SkipLang>[\\@]"~"[a-zA-Z-]*            { /* language switch */
1937                                           QCString langId(&yytext[2]);
1938                                           if (langId.isEmpty() ||
1939                                               qstricmp(Config_getEnumAsString(OUTPUT_LANGUAGE).data(),langId.data())==0)
1940                                           { // enable language specific section
1941                                             BEGIN(Comment);
1942                                           }
1943                                         }
1944 <SkipLang>[^*@\\\n]*                    { /* any character not a *, @, backslash or new line */
1945                                         }
1946 <SkipLang>{DOCNL}                       { /* new line in verbatim block */
1947                                           if (*yytext=='\n') yyextra->lineNr++;
1948                                         }
1949 <SkipLang>.                             { /* any other character */
1950                                         }
1951 
1952   /* ----- handle arguments of the cite command ------- */
1953 
1954 <CiteLabel>{CITEID}                     { // found argument
1955                                           addCite(yyscanner);
1956                                           addOutput(yyscanner,yytext);
1957                                           BEGIN(Comment);
1958                                         }
1959 <CiteLabel>{DOCNL}                      { // missing argument
1960                                           warn(yyextra->fileName,yyextra->lineNr,
1961                                               "\\cite command has no label"
1962                                               );
1963                                           //if (*yytext=='\n') yyextra->lineNr++;
1964                                           //addOutput(yyscanner,'\n');
1965                                           unput_string(yytext,yyleng);
1966                                           BEGIN( Comment );
1967                                         }
1968 <CiteLabel>.                            { // invalid character for cite label
1969                                            warn(yyextra->fileName,yyextra->lineNr,
1970                                               "Invalid or missing cite label"
1971                                               );
1972                                           BEGIN(Comment);
1973                                         }
1974 
1975   /* ----- handle argument of the copydoc command ------- */
1976 
1977 <CopyDoc><<EOF>>                        {
1978                                           setOutput(yyscanner,OutputDoc);
1979                                           addOutput(yyscanner," \\ilinebr\\ilinebr\\copydetails ");
1980                                           addOutput(yyscanner,yyextra->copyDocArg);
1981                                           addOutput(yyscanner,"\n");
1982                                           BEGIN(Comment);
1983                                         }
1984 <CopyDoc>{DOCNL}                        {
1985                                           if (*yytext=='\n') yyextra->lineNr++;
1986                                           if (yyextra->braceCount==0)
1987                                           {
1988                                             setOutput(yyscanner,OutputDoc);
1989                                             addOutput(yyscanner," \\ilinebr\\ilinebr\\copydetails ");
1990                                             addOutput(yyscanner,yyextra->copyDocArg);
1991                                             addOutput(yyscanner,"\n");
1992                                             BEGIN(Comment);
1993                                           }
1994                                         }
1995 <CopyDoc>{LC}                           { // line continuation
1996                                           yyextra->lineNr++;
1997                                         }
1998 <CopyDoc>[^@\\\n()]+                    { // non-special characters
1999                                           yyextra->copyDocArg+=yytext;
2000                                           addOutput(yyscanner,yytext);
2001                                         }
2002 <CopyDoc>"("                            {
2003                                           yyextra->copyDocArg+=yytext;
2004                                           addOutput(yyscanner,yytext);
2005                                           yyextra->braceCount++;
2006                                         }
2007 <CopyDoc>")"                            {
2008                                           yyextra->copyDocArg+=yytext;
2009                                           addOutput(yyscanner,yytext);
2010                                           yyextra->braceCount--;
2011                                         }
2012 <CopyDoc>.                              {
2013                                           yyextra->copyDocArg+=yytext;
2014                                           addOutput(yyscanner,yytext);
2015                                         }
2016 
2017  /*
2018 <*>.  { fprintf(stderr,"Lex scanner %s %sdefault rule for state %s: #%s#\n", __FILE__,yyextra->fileName ? ("(" + yyextra->fileName +") ").data(): "",stateToString(YY_START),yytext);}
2019 <*>\n  { fprintf(stderr,"Lex scanner %s %sdefault rule newline for state %s.\n", __FILE__, yyextra->fileName ? ("(" + yyextra->fileName +") ").data(): "",stateToString(YY_START));}
2020   */
2021 
2022 %%
2023 
2024 //----------------------------------------------------------------------------
2025 
2026 static bool handleBrief(yyscan_t yyscanner,const QCString &, const StringVector &)
2027 {
2028   //printf("handleBrief\n");
2029   setOutput(yyscanner,OutputBrief);
2030   return FALSE;
2031 }
2032 
2033 static bool handleFn(yyscan_t yyscanner,const QCString &, const StringVector &)
2034 {
2035   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2036   bool stop=makeStructuralIndicator(yyscanner,Entry::MEMBERDOC_SEC);
2037   yyextra->functionProto.resize(0);
2038   yyextra->braceCount=0;
2039   BEGIN(FnParam);
2040   return stop;
2041 }
2042 
2043 static bool handleDef(yyscan_t yyscanner,const QCString &, const StringVector &)
2044 {
2045   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2046   bool stop=makeStructuralIndicator(yyscanner,Entry::DEFINEDOC_SEC);
2047   yyextra->functionProto.resize(0);
2048   BEGIN(FnParam);
2049   return stop;
2050 }
2051 
2052 static bool handleOverload(yyscan_t yyscanner,const QCString &, const StringVector &)
2053 {
2054   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2055   yyextra->functionProto.resize(0);
2056   BEGIN(OverloadParam);
2057   return FALSE;
2058 }
2059 
2060 static bool handleEnum(yyscan_t yyscanner,const QCString &, const StringVector &)
2061 {
2062   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2063   bool stop=makeStructuralIndicator(yyscanner,Entry::ENUMDOC_SEC);
2064   BEGIN(EnumDocArg1);
2065   return stop;
2066 }
2067 
2068 static bool handleDefGroup(yyscan_t yyscanner,const QCString &, const StringVector &)
2069 {
2070   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2071   bool stop=makeStructuralIndicator(yyscanner,Entry::GROUPDOC_SEC);
2072   yyextra->current->groupDocType = Entry::GROUPDOC_NORMAL;
2073   BEGIN( GroupDocArg1 );
2074   return stop;
2075 }
2076 
2077 static bool handleAddToGroup(yyscan_t yyscanner,const QCString &, const StringVector &)
2078 {
2079   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2080   bool stop=makeStructuralIndicator(yyscanner,Entry::GROUPDOC_SEC);
2081   yyextra->current->groupDocType = Entry::GROUPDOC_ADD;
2082   BEGIN( GroupDocArg1 );
2083   return stop;
2084 }
2085 
2086 static bool handleWeakGroup(yyscan_t yyscanner,const QCString &, const StringVector &)
2087 {
2088   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2089   bool stop=makeStructuralIndicator(yyscanner,Entry::GROUPDOC_SEC);
2090   yyextra->current->groupDocType = Entry::GROUPDOC_WEAK;
2091   BEGIN( GroupDocArg1 );
2092   return stop;
2093 }
2094 
2095 static bool handleNamespace(yyscan_t yyscanner,const QCString &, const StringVector &)
2096 {
2097   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2098   bool stop=makeStructuralIndicator(yyscanner,Entry::NAMESPACEDOC_SEC);
2099   BEGIN( NameSpaceDocArg1 );
2100   return stop;
2101 }
2102 
2103 static bool handlePackage(yyscan_t yyscanner,const QCString &, const StringVector &)
2104 {
2105   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2106   bool stop=makeStructuralIndicator(yyscanner,Entry::PACKAGEDOC_SEC);
2107   BEGIN( PackageDocArg1 );
2108   return stop;
2109 }
2110 
2111 static bool handleClass(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2112 {
2113   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2114   bool stop=makeStructuralIndicator(yyscanner,Entry::CLASSDOC_SEC);
2115   yyextra->currentCmd = cmd;
2116   BEGIN( ClassDocArg1 );
2117   return stop;
2118 }
2119 
2120 static bool handleConcept(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2121 {
2122   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2123   bool stop=makeStructuralIndicator(yyscanner,Entry::CONCEPTDOC_SEC);
2124   yyextra->currentCmd = cmd;
2125   BEGIN( ConceptDocArg1 );
2126   return stop;
2127 }
2128 
2129 static bool handleHeaderFile(yyscan_t yyscanner,const QCString &, const StringVector &)
2130 {
2131   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2132   BEGIN( ClassDocArg2 );
2133   return FALSE;
2134 }
2135 
2136 static bool handleProtocol(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2137 { // Obj-C protocol
2138   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2139   bool stop=makeStructuralIndicator(yyscanner,Entry::PROTOCOLDOC_SEC);
2140   yyextra->currentCmd = cmd;
2141   BEGIN( ClassDocArg1 );
2142   return stop;
2143 }
2144 
2145 static bool handleCategory(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2146 { // Obj-C category
2147   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2148   bool stop=makeStructuralIndicator(yyscanner,Entry::CATEGORYDOC_SEC);
2149   yyextra->currentCmd = cmd;
2150   BEGIN( CategoryDocArg1 );
2151   return stop;
2152 }
2153 
2154 static bool handleUnion(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2155 {
2156   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2157   bool stop=makeStructuralIndicator(yyscanner,Entry::UNIONDOC_SEC);
2158   yyextra->currentCmd = cmd;
2159   BEGIN( ClassDocArg1 );
2160   return stop;
2161 }
2162 
2163 static bool handleStruct(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2164 {
2165   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2166   bool stop=makeStructuralIndicator(yyscanner,Entry::STRUCTDOC_SEC);
2167   yyextra->currentCmd = cmd;
2168   BEGIN( ClassDocArg1 );
2169   return stop;
2170 }
2171 
2172 static bool handleInterface(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2173 {
2174   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2175   bool stop=makeStructuralIndicator(yyscanner,Entry::INTERFACEDOC_SEC);
2176   yyextra->currentCmd = cmd;
2177   BEGIN( ClassDocArg1 );
2178   return stop;
2179 }
2180 
2181 static bool handleIdlException(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2182 {
2183   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2184   bool stop=makeStructuralIndicator(yyscanner,Entry::EXCEPTIONDOC_SEC);
2185   yyextra->currentCmd = cmd;
2186   BEGIN( ClassDocArg1 );
2187   return stop;
2188 }
2189 
2190 static bool handlePage(yyscan_t yyscanner,const QCString &, const StringVector &)
2191 {
2192   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2193   bool stop=makeStructuralIndicator(yyscanner,Entry::PAGEDOC_SEC);
2194   BEGIN( PageDocArg1 );
2195   return stop;
2196 }
2197 
2198 static bool handleMainpage(yyscan_t yyscanner,const QCString &, const StringVector &)
2199 {
2200   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2201   bool stop=makeStructuralIndicator(yyscanner,Entry::MAINPAGEDOC_SEC);
2202   if (!stop)
2203   {
2204     yyextra->current->name = "mainpage";
2205   }
2206   setOutput(yyscanner,OutputDoc);
2207   BEGIN( PageDocArg2 );
2208   return stop;
2209 }
2210 
2211 static bool handleFile(yyscan_t yyscanner,const QCString &, const StringVector &)
2212 {
2213   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2214   bool stop=makeStructuralIndicator(yyscanner,Entry::FILEDOC_SEC);
2215   if (!stop)
2216   {
2217     yyextra->current->name = yyextra->fileName;
2218   }
2219   BEGIN( FileDocArg1 );
2220   return stop;
2221 }
2222 
2223 static bool handleParam(yyscan_t yyscanner,const QCString &, const StringVector &)
2224 {
2225   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2226   // we need process param and retval arguments to escape leading underscores in case of
2227   // markdown processing, see bug775493
2228   addOutput(yyscanner,"@param ");
2229   BEGIN( ParamArg1 );
2230   return FALSE;
2231 }
2232 
2233 static bool handleRetval(yyscan_t yyscanner,const QCString &, const StringVector &)
2234 {
2235   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2236   addOutput(yyscanner,"@retval ");
2237   BEGIN( ParamArg1 );
2238   return FALSE;
2239 }
2240 
2241 static bool handleDir(yyscan_t yyscanner,const QCString &, const StringVector &)
2242 {
2243   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2244   bool stop=makeStructuralIndicator(yyscanner,Entry::DIRDOC_SEC);
2245   if (!stop) yyextra->current->name = yyextra->fileName;
2246   BEGIN( FileDocArg1 );
2247   return stop;
2248 }
2249 
2250 static bool handleExample(yyscan_t yyscanner,const QCString &cmd, const StringVector &optList)
2251 {
2252   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2253   Entry::Sections section=Entry::EXAMPLE_SEC;
2254   for (const auto &opt : optList)
2255   {
2256     if (opt=="lineno")
2257     {
2258       section=Entry::EXAMPLE_LINENO_SEC;
2259     }
2260     else
2261     {
2262       warn(yyextra->fileName,yyextra->lineNr,
2263           "unsupported option '%s' for command '\\%s'",opt.c_str(),qPrint(cmd));
2264     }
2265   }
2266   bool stop=makeStructuralIndicator(yyscanner,section);
2267   if (!stop) yyextra->current->name = yyextra->fileName;
2268   BEGIN( FileDocArg1 );
2269   return stop;
2270 }
2271 
2272 static bool handleDetails(yyscan_t yyscanner,const QCString &, const StringVector &)
2273 {
2274   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2275   if (yyextra->inContext!=OutputBrief)
2276   {
2277     addOutput(yyscanner,"\\ilinebr\\ilinebr "); // treat @details outside brief description
2278                                                 // as a new paragraph
2279   }
2280   setOutput(yyscanner,OutputDoc);
2281   return FALSE;
2282 }
2283 
2284 static bool handleRaiseWarning(yyscan_t yyscanner,const QCString &, const StringVector &)
2285 {
2286   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2287   yyextra->raiseWarning = "";
2288   BEGIN( RaiseWarning );
2289   return FALSE;
2290 }
2291 
2292 static bool handleNoop(yyscan_t yyscanner,const QCString &, const StringVector &)
2293 {
2294   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2295   BEGIN( Noop );
2296   return FALSE;
2297 }
2298 
2299 static bool handleName(yyscan_t yyscanner,const QCString &, const StringVector &)
2300 {
2301   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2302   bool stop=makeStructuralIndicator(yyscanner,Entry::MEMBERGRP_SEC);
2303   if (!stop)
2304   {
2305     yyextra->docGroup.clearHeader();
2306     BEGIN( NameParam );
2307     if (!yyextra->docGroup.isEmpty()) // end of previous member group
2308     {
2309       yyextra->docGroup.close(yyextra->current,yyextra->fileName,yyextra->lineNr,TRUE,true);
2310     }
2311   }
2312   return stop;
2313 }
2314 
2315 static bool handleTodo(yyscan_t yyscanner,const QCString &, const StringVector &)
2316 {
2317   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2318   yyextra->newXRefKind = XRef_Todo;
2319   setOutput(yyscanner,OutputXRef);
2320   yyextra->xrefKind = XRef_Todo;
2321   return FALSE;
2322 }
2323 
2324 static bool handleTest(yyscan_t yyscanner,const QCString &, const StringVector &)
2325 {
2326   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2327   yyextra->newXRefKind = XRef_Test;
2328   setOutput(yyscanner,OutputXRef);
2329   yyextra->xrefKind = XRef_Test;
2330   return FALSE;
2331 }
2332 
2333 static bool handleBug(yyscan_t yyscanner,const QCString &, const StringVector &)
2334 {
2335   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2336   yyextra->newXRefKind = XRef_Bug;
2337   setOutput(yyscanner,OutputXRef);
2338   yyextra->xrefKind = XRef_Bug;
2339   return FALSE;
2340 }
2341 
2342 static bool handleDeprecated(yyscan_t yyscanner,const QCString &, const StringVector &)
2343 {
2344   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2345   yyextra->newXRefKind = XRef_Deprecated;
2346   setOutput(yyscanner,OutputXRef);
2347   yyextra->xrefKind = XRef_Deprecated;
2348   return FALSE;
2349 }
2350 
2351 static bool handleXRefItem(yyscan_t yyscanner,const QCString &, const StringVector &)
2352 {
2353   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2354   yyextra->newXRefKind = XRef_Item;
2355   BEGIN(XRefItemParam1);
2356   return FALSE;
2357 }
2358 
2359 static bool handleParBlock(yyscan_t yyscanner,const QCString &, const StringVector &)
2360 {
2361   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2362   if (yyextra->insideParBlock)
2363   {
2364     warn(yyextra->fileName,yyextra->lineNr,
2365         "found \\parblock command while already in a parblock!");
2366   }
2367   if (!yyextra->spaceBeforeCmd.isEmpty())
2368   {
2369     addOutput(yyscanner,yyextra->spaceBeforeCmd);
2370     yyextra->spaceBeforeCmd.resize(0);
2371   }
2372   addOutput(yyscanner,"@parblock ");
2373   yyextra->insideParBlock = TRUE;
2374   return FALSE;
2375 }
2376 
2377 static bool handleEndParBlock(yyscan_t yyscanner,const QCString &, const StringVector &)
2378 {
2379   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2380   if (!yyextra->insideParBlock)
2381   {
2382     warn(yyextra->fileName,yyextra->lineNr,
2383         "found \\endparblock command without matching \\parblock!");
2384   }
2385   addOutput(yyscanner,"@endparblock");
2386   setOutput(yyscanner,OutputDoc); // to end a parblock inside a xrefitem like context
2387   yyextra->insideParBlock = FALSE;
2388   return FALSE;
2389 }
2390 
2391 static bool handleRelated(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2392 {
2393   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2394   if (!yyextra->current->relates.isEmpty())
2395   {
2396     warn(yyextra->fileName,yyextra->lineNr,
2397         "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition");
2398   }
2399   yyextra->current->relatesType = Simple;
2400   yyextra->currentCmd = cmd;
2401   BEGIN(RelatesParam1);
2402   return FALSE;
2403 }
2404 
2405 static bool handleRelatedAlso(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2406 {
2407   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2408   if (!yyextra->current->relates.isEmpty())
2409   {
2410     warn(yyextra->fileName,yyextra->lineNr,
2411         "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition");
2412   }
2413   yyextra->current->relatesType = Duplicate;
2414   yyextra->currentCmd = cmd;
2415   BEGIN(RelatesParam1);
2416   return FALSE;
2417 }
2418 
2419 static bool handleMemberOf(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2420 {
2421   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2422   if (!yyextra->current->relates.isEmpty())
2423   {
2424     warn(yyextra->fileName,yyextra->lineNr,
2425         "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition");
2426   }
2427   yyextra->current->relatesType = MemberOf;
2428   yyextra->currentCmd = cmd;
2429   BEGIN(RelatesParam1);
2430   return FALSE;
2431 }
2432 
2433 static bool handleRefItem(yyscan_t yyscanner,const QCString &, const StringVector &)
2434 {
2435   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2436   addOutput(yyscanner,"@refitem ");
2437   BEGIN(LineParam);
2438   return FALSE;
2439 }
2440 
2441 static bool handleSection(yyscan_t yyscanner,const QCString &s, const StringVector &)
2442 {
2443   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2444   setOutput(yyscanner,OutputDoc);
2445   addOutput(yyscanner,"@"+s+" ");
2446   BEGIN(SectionLabel);
2447   if      (s=="section")       yyextra->sectionLevel=1;
2448   else if (s=="subsection")    yyextra->sectionLevel=2;
2449   else if (s=="subsubsection") yyextra->sectionLevel=3;
2450   else if (s=="paragraph")     yyextra->sectionLevel=4;
2451   return FALSE;
2452 }
2453 
2454 static bool handleSubpage(yyscan_t yyscanner,const QCString &s, const StringVector &)
2455 {
2456   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2457   if (yyextra->current->section!=Entry::EMPTY_SEC &&
2458       yyextra->current->section!=Entry::PAGEDOC_SEC &&
2459       yyextra->current->section!=Entry::MAINPAGEDOC_SEC
2460      )
2461   {
2462     warn(yyextra->fileName,yyextra->lineNr,
2463         "found \\subpage command in a comment block that is not marked as a page!");
2464   }
2465   if (!yyextra->spaceBeforeCmd.isEmpty())
2466   {
2467     addOutput(yyscanner,yyextra->spaceBeforeCmd);
2468     yyextra->spaceBeforeCmd.resize(0);
2469   }
2470   addOutput(yyscanner,"@"+s+" ");
2471   BEGIN(SubpageLabel);
2472   return FALSE;
2473 }
2474 
2475 static bool handleAnchor(yyscan_t yyscanner,const QCString &s, const StringVector &)
2476 {
2477   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2478   addOutput(yyscanner,"@"+s+" ");
2479   BEGIN(AnchorLabel);
2480   return FALSE;
2481 }
2482 
2483 static bool handleImage(yyscan_t yyscanner,const QCString &s, const StringVector &optList)
2484 {
2485   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2486   for (const auto &opt : optList)
2487   {
2488     QCString locOpt(opt);
2489     locOpt = locOpt.stripWhiteSpace();
2490     if (locOpt.lower().startsWith("anchor:"))
2491     {
2492       addAnchor(yyscanner,locOpt.mid(7));
2493       break; // real option handling will be done later on
2494     }
2495   }
2496   if (optList.empty())
2497   {
2498     addOutput(yyscanner,"@"+s+" ");
2499   }
2500   else
2501   {
2502     addOutput(yyscanner,"@"+s+"{"+QCString(join(optList,","))+"} ");
2503   }
2504   BEGIN(Comment);
2505   return FALSE;
2506 }
2507 
2508 static bool handleCite(yyscan_t yyscanner,const QCString &s, const StringVector &)
2509 {
2510   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2511   if (!yyextra->spaceBeforeCmd.isEmpty())
2512   {
2513     addOutput(yyscanner,yyextra->spaceBeforeCmd);
2514     yyextra->spaceBeforeCmd.resize(0);
2515   }
2516   addOutput(yyscanner,"@"+s+" ");
2517   BEGIN(CiteLabel);
2518   return FALSE;
2519 }
2520 
2521 static bool handleFormatBlock(yyscan_t yyscanner,const QCString &s, const StringVector &optList)
2522 {
2523   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2524   if (!yyextra->spaceBeforeCmd.isEmpty())
2525   {
2526     addOutput(yyscanner,yyextra->spaceBeforeCmd);
2527     yyextra->spaceBeforeCmd.resize(0);
2528   }
2529   if (optList.empty())
2530   {
2531     addOutput(yyscanner,"@"+s+" ");
2532   }
2533   else
2534   {
2535     addOutput(yyscanner,"@"+s+"{"+QCString(join(optList,","))+"} ");
2536   }
2537   //printf("handleFormatBlock(%s) with option(%s)\n",qPrint(s),qPrint(opt));
2538   yyextra->blockName=s;
2539   yyextra->commentCount=0;
2540   BEGIN(FormatBlock);
2541   return FALSE;
2542 }
2543 
2544 static bool handleAddIndex(yyscan_t yyscanner,const QCString &, const StringVector &)
2545 {
2546   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2547   addOutput(yyscanner,"@addindex ");
2548   BEGIN(LineParam);
2549   return FALSE;
2550 }
2551 
2552 static bool handleIf(yyscan_t yyscanner,const QCString &, const StringVector &)
2553 {
2554   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2555   yyextra->enabledSectionFound=FALSE;
2556   yyextra->guardType = Guard_If;
2557   yyextra->spaceBeforeIf = yyextra->spaceBeforeCmd;
2558   BEGIN(GuardParam);
2559   return FALSE;
2560 }
2561 
2562 static bool handleIfNot(yyscan_t yyscanner,const QCString &, const StringVector &)
2563 {
2564   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2565   yyextra->enabledSectionFound=FALSE;
2566   yyextra->guardType = Guard_IfNot;
2567   yyextra->spaceBeforeIf = yyextra->spaceBeforeCmd;
2568   BEGIN(GuardParam);
2569   return FALSE;
2570 }
2571 
2572 static bool handleElseIf(yyscan_t yyscanner,const QCString &, const StringVector &)
2573 {
2574   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2575   if (yyextra->guards.empty())
2576   {
2577     warn(yyextra->fileName,yyextra->lineNr,
2578         "found \\else without matching start command");
2579   }
2580   else
2581   {
2582     yyextra->guardType = yyextra->enabledSectionFound ? Guard_Skip : Guard_If;
2583     yyextra->spaceBeforeIf = yyextra->spaceBeforeCmd;
2584     BEGIN(GuardParam);
2585   }
2586   return FALSE;
2587 }
2588 
2589 static bool handleElse(yyscan_t yyscanner,const QCString &, const StringVector &)
2590 {
2591   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2592   if (yyextra->guards.empty())
2593   {
2594     warn(yyextra->fileName,yyextra->lineNr,
2595         "found \\else without matching start command");
2596   }
2597   else
2598   {
2599     yyextra->spaceBeforeIf = yyextra->spaceBeforeCmd;
2600     BEGIN( SkipGuardedSection );
2601   }
2602   return FALSE;
2603 }
2604 
2605 static bool handleEndIf(yyscan_t yyscanner,const QCString &, const StringVector &)
2606 {
2607   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2608   if (yyextra->guards.empty())
2609   {
2610     warn(yyextra->fileName,yyextra->lineNr,
2611         "found \\endif without matching start command");
2612   }
2613   else
2614   {
2615     yyextra->guards.pop();
2616   }
2617   yyextra->enabledSectionFound=FALSE;
2618   if (!yyextra->spaceBeforeCmd.isEmpty())
2619   {
2620     addOutput(yyscanner,yyextra->spaceBeforeCmd);
2621     yyextra->spaceBeforeCmd.resize(0);
2622   }
2623   BEGIN( GuardParamEnd );
2624   return FALSE;
2625 }
2626 
2627 static bool handleIngroup(yyscan_t yyscanner,const QCString &, const StringVector &)
2628 {
2629   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2630   yyextra->inGroupParamFound=FALSE;
2631   BEGIN( InGroupParam );
2632   return FALSE;
2633 }
2634 
2635 static bool handleNoSubGrouping(yyscan_t yyscanner,const QCString &, const StringVector &)
2636 {
2637   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2638   yyextra->current->subGrouping = FALSE;
2639   return FALSE;
2640 }
2641 
2642 static bool handleShowInitializer(yyscan_t yyscanner,const QCString &, const StringVector &)
2643 {
2644   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2645   yyextra->current->initLines = 100000; // ON
2646   return FALSE;
2647 }
2648 
2649 static bool handleHideInitializer(yyscan_t yyscanner,const QCString &, const StringVector &)
2650 {
2651   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2652   yyextra->current->initLines = 0; // OFF
2653   return FALSE;
2654 }
2655 
2656 static bool handleCallgraph(yyscan_t yyscanner,const QCString &, const StringVector &)
2657 {
2658   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2659   yyextra->current->callGraph = TRUE; // ON
2660   return FALSE;
2661 }
2662 
2663 static bool handleHideCallgraph(yyscan_t yyscanner,const QCString &, const StringVector &)
2664 {
2665   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2666   yyextra->current->callGraph = FALSE; // OFF
2667   return FALSE;
2668 }
2669 
2670 static bool handleCallergraph(yyscan_t yyscanner,const QCString &, const StringVector &)
2671 {
2672   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2673   yyextra->current->callerGraph = TRUE; // ON
2674   return FALSE;
2675 }
2676 
2677 static bool handleHideCallergraph(yyscan_t yyscanner,const QCString &, const StringVector &)
2678 {
2679   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2680   yyextra->current->callerGraph = FALSE; // OFF
2681   return FALSE;
2682 }
2683 
2684 static bool handleReferencedByRelation(yyscan_t yyscanner,const QCString &, const StringVector &)
2685 {
2686   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2687   yyextra->current->referencedByRelation = TRUE; // ON
2688   return FALSE;
2689 }
2690 
2691 static bool handleHideReferencedByRelation(yyscan_t yyscanner,const QCString &, const StringVector &)
2692 {
2693   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2694   yyextra->current->referencedByRelation = FALSE; // OFF
2695   return FALSE;
2696 }
2697 
2698 static bool handleReferencesRelation(yyscan_t yyscanner,const QCString &, const StringVector &)
2699 {
2700   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2701   yyextra->current->referencesRelation = TRUE; // ON
2702   return FALSE;
2703 }
2704 
2705 static bool handleHideReferencesRelation(yyscan_t yyscanner,const QCString &, const StringVector &)
2706 {
2707   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2708   yyextra->current->referencesRelation = FALSE; // OFF
2709   return FALSE;
2710 }
2711 
2712 static bool handleInternal(yyscan_t yyscanner,const QCString &, const StringVector &)
2713 {
2714   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2715   if (!Config_getBool(INTERNAL_DOCS))
2716   {
2717     // make sure some whitespace before a \internal command
2718     // is not treated as "documentation"
2719     if (yyextra->current->doc.stripWhiteSpace().isEmpty())
2720     {
2721       yyextra->current->doc.resize(0);
2722     }
2723     yyextra->condCount=0;
2724     BEGIN( SkipInternal );
2725   }
2726   else
2727   {
2728     // re-enabled for bug640828
2729     addOutput(yyscanner," \\internal ");
2730     yyextra->inInternalDocs = TRUE;
2731   }
2732   return FALSE;
2733 }
2734 
2735 static bool handleStatic(yyscan_t yyscanner,const QCString &, const StringVector &)
2736 {
2737   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2738   yyextra->current->stat = TRUE;
2739   return FALSE;
2740 }
2741 
2742 static bool handlePure(yyscan_t yyscanner,const QCString &, const StringVector &)
2743 {
2744   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2745   yyextra->current->virt = Pure;
2746   return FALSE;
2747 }
2748 
2749 static bool handlePrivate(yyscan_t yyscanner,const QCString &, const StringVector &)
2750 {
2751   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2752   yyextra->current->protection = Private;
2753   return FALSE;
2754 }
2755 
2756 static bool handlePrivateSection(yyscan_t yyscanner,const QCString &, const StringVector &)
2757 {
2758   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2759   yyextra->current->protection = yyextra->protection = Private;
2760   return FALSE;
2761 }
2762 
2763 static bool handleProtected(yyscan_t yyscanner,const QCString &, const StringVector &)
2764 {
2765   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2766   yyextra->current->protection = Protected;
2767   return FALSE;
2768 }
2769 
2770 static bool handleProtectedSection(yyscan_t yyscanner,const QCString &, const StringVector &)
2771 {
2772   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2773   yyextra->current->protection = yyextra->protection = Protected ;
2774   return FALSE;
2775 }
2776 
2777 static bool handlePublic(yyscan_t yyscanner,const QCString &, const StringVector &)
2778 {
2779   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2780   yyextra->current->protection = Public;
2781   return FALSE;
2782 }
2783 
2784 static bool handlePublicSection(yyscan_t yyscanner,const QCString &, const StringVector &)
2785 {
2786   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2787   yyextra->current->protection = yyextra->protection = Public;
2788   return FALSE;
2789 }
2790 
2791 static bool handleToc(yyscan_t yyscanner,const QCString &, const StringVector &optList)
2792 {
2793   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2794   if (yyextra->current->section==Entry::PAGEDOC_SEC ||
2795       yyextra->current->section==Entry::MAINPAGEDOC_SEC)
2796   {
2797     for (const auto &opt_ : optList)
2798     {
2799       QCString opt = QCString(opt_).stripWhiteSpace().lower();
2800       char dum;
2801       int level = 5;
2802       int i = opt.find(':');
2803       if (i>0)  // found ':' but not on position 0 what would mean just a level
2804       {
2805         if (sscanf(opt.right(opt.length() - i - 1).data(),"%d%c",&level,&dum) != 1)
2806         {
2807           warn(yyextra->fileName,yyextra->lineNr,"Unknown option:level specified with \\tableofcontents: '%s'", qPrint(QCString(opt_).stripWhiteSpace()));
2808           opt = "";
2809         }
2810         else
2811         {
2812           level = (level > 5 ? 5 : level);
2813           level = (level <= 0 ? 5 : level);
2814           opt = opt.left(i).stripWhiteSpace();
2815         }
2816       }
2817       if (!opt.isEmpty())
2818       {
2819         if (opt == "html")
2820         {
2821           yyextra->current->localToc.enableHtml(level);
2822         }
2823         else if (opt == "latex")
2824         {
2825           yyextra->current->localToc.enableLatex(level);
2826         }
2827         else if (opt == "xml")
2828         {
2829           yyextra->current->localToc.enableXml(level);
2830         }
2831         else if (opt == "docbook")
2832         {
2833           yyextra->current->localToc.enableDocbook(level);
2834         }
2835         else
2836         {
2837           warn(yyextra->fileName,yyextra->lineNr,"Unknown option specified with \\tableofcontents: '%s'", qPrint(QCString(opt_).stripWhiteSpace()));
2838         }
2839       }
2840     }
2841     if (yyextra->current->localToc.nothingEnabled())
2842     {
2843       // for backward compatibility
2844       yyextra->current->localToc.enableHtml(5);
2845       yyextra->current->localToc.enableXml(5);
2846     }
2847   }
2848   return FALSE;
2849 }
2850 
2851 static bool handleInherit(yyscan_t yyscanner,const QCString &, const StringVector &)
2852 {
2853   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2854   BEGIN(InheritParam);
2855   return FALSE;
2856 }
2857 
2858 static bool handleExtends(yyscan_t yyscanner,const QCString &cmd, const StringVector &)
2859 {
2860   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2861   yyextra->currentCmd = cmd;
2862   BEGIN(ExtendsParam);
2863   return FALSE;
2864 }
2865 
2866 static bool handleCopyBrief(yyscan_t yyscanner,const QCString &, const StringVector &)
2867 {
2868   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2869   if (yyextra->current->brief.isEmpty() && yyextra->current->doc.isEmpty())
2870   { // if we don't have a brief or detailed description yet,
2871     // then the @copybrief should end up in the brief description.
2872     // otherwise it will be copied inline (see bug691315 & bug700788)
2873     setOutput(yyscanner,OutputBrief);
2874   }
2875   if (!yyextra->spaceBeforeCmd.isEmpty())
2876   {
2877     addOutput(yyscanner,yyextra->spaceBeforeCmd);
2878     yyextra->spaceBeforeCmd.resize(0);
2879   }
2880   addOutput(yyscanner,"\\copybrief ");
2881   return FALSE;
2882 }
2883 
2884 static bool handleCopyDetails(yyscan_t yyscanner,const QCString &, const StringVector &)
2885 {
2886   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2887   setOutput(yyscanner,OutputDoc);
2888   if (!yyextra->spaceBeforeCmd.isEmpty())
2889   {
2890     addOutput(yyscanner,yyextra->spaceBeforeCmd);
2891     yyextra->spaceBeforeCmd.resize(0);
2892   }
2893   addOutput(yyscanner,"\\copydetails ");
2894   return FALSE;
2895 }
2896 
2897 static bool handleCopyDoc(yyscan_t yyscanner,const QCString &, const StringVector &)
2898 {
2899   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2900   if (yyextra->current->brief.isEmpty() && yyextra->current->doc.isEmpty())
2901   { // if we don't have a brief or detailed description yet,
2902     // then the @copybrief should end up in the brief description.
2903     // otherwise it will be copied inline (see bug691315 & bug700788)
2904     setOutput(yyscanner,OutputBrief);
2905   }
2906   if (!yyextra->spaceBeforeCmd.isEmpty())
2907   {
2908     addOutput(yyscanner,yyextra->spaceBeforeCmd);
2909     yyextra->spaceBeforeCmd.resize(0);
2910   }
2911   addOutput(yyscanner,"\\copybrief ");
2912   yyextra->copyDocArg.resize(0);
2913   yyextra->braceCount = 0;
2914   BEGIN(CopyDoc);
2915   return FALSE;
2916 }
2917 
2918 //-----------------------------------------------------------------------------------------
2919 
2920 static void initParser(yyscan_t yyscanner)
2921 {
2922   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2923   yyextra->sectionLabel.resize(0);
2924   yyextra->sectionTitle.resize(0);
2925   yyextra->docGroup.clearHeader();
2926   yyextra->insideParBlock = FALSE;
2927 }
2928 
2929 
2930 static bool getDocSectionName(int s)
2931 {
2932   switch(s)
2933   {
2934     case Entry::CLASSDOC_SEC:
2935     case Entry::STRUCTDOC_SEC:
2936     case Entry::UNIONDOC_SEC:
2937     case Entry::EXCEPTIONDOC_SEC:
2938     case Entry::NAMESPACEDOC_SEC:
2939     case Entry::PROTOCOLDOC_SEC:
2940     case Entry::CATEGORYDOC_SEC:
2941     case Entry::ENUMDOC_SEC:
2942     case Entry::PAGEDOC_SEC:
2943     case Entry::VARIABLEDOC_SEC:
2944     case Entry::MEMBERDOC_SEC:
2945     case Entry::OVERLOADDOC_SEC:
2946     case Entry::FILEDOC_SEC:
2947     case Entry::DEFINEDOC_SEC:
2948     case Entry::GROUPDOC_SEC:
2949     case Entry::MAINPAGEDOC_SEC:
2950     case Entry::PACKAGEDOC_SEC:
2951     case Entry::DIRDOC_SEC:
2952     case Entry::EXAMPLE_SEC:
2953     case Entry::MEMBERGRP_SEC:
2954     case Entry::CONCEPTDOC_SEC:
2955       return TRUE;
2956     default:
2957       return FALSE;
2958   }
2959 }
2960 
2961 //-----------------------------------------------------------------------------
2962 
2963 static bool makeStructuralIndicator(yyscan_t yyscanner,Entry::Sections s)
2964 {
2965   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2966   //printf("yyextra->current->section=%x\n",yyextra->current->section);
2967   if (getDocSectionName(yyextra->current->section))
2968   {
2969     return TRUE;
2970   }
2971   else
2972   {
2973     yyextra->needNewEntry = TRUE;
2974     yyextra->current->section = s;
2975     yyextra->current->fileName = yyextra->fileName;
2976     yyextra->current->startLine = yyextra->lineNr;
2977     yyextra->current->docLine = yyextra->lineNr;
2978     return FALSE;
2979   }
2980 }
2981 
2982 //-----------------------------------------------------------------
2983 
2984 static void lineCount(yyscan_t yyscanner)
2985 {
2986   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2987   for( const char* c = yytext ; *c ; ++c )
2988     yyextra->lineNr += (*c == '\n') ;
2989 }
2990 
2991 //-----------------------------------------------------------------
2992 
2993 static QCString stripQuotes(const char *s)
2994 {
2995   QCString name;
2996   if (s==0 || *s==0) return name;
2997   name=s;
2998   if (name.at(0)=='"' && name.at(name.length()-1)=='"')
2999   {
3000     name=name.mid(1,name.length()-2);
3001   }
3002   return name;
3003 }
3004 
3005 //-----------------------------------------------------------------
3006 
3007 static void addXRefItem(yyscan_t yyscanner,
3008                         const QCString &listName,const QCString &itemTitle,
3009                         const QCString &listTitle,bool append)
3010 {
3011   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3012   if (listName.isEmpty()) return;
3013   //printf("addXRefItem(%s,%s,%s,%d)\n",listName,itemTitle,listTitle,append);
3014 
3015   std::unique_lock<std::mutex> lock(g_sectionMutex);
3016 
3017   RefList *refList = RefListManager::instance().add(listName,listTitle,itemTitle);
3018   RefItem *item = 0;
3019   for (auto it = yyextra->current->sli.rbegin(); it != yyextra->current->sli.rend(); ++it)
3020   {
3021     RefItem *i = *it;
3022     if (i && i->list()->listName()==listName)
3023     {
3024       //printf("found %s lii->type=%s\n",listName,qPrint(i->list()->listName()));
3025       item = i;
3026       break;
3027     }
3028   }
3029   if (item && append) // already found item of same type just before this one
3030   {
3031     //printf("listName=%s item id = %d existing\n",listName,item->id());
3032     item->setText(item->text() + " <p>" + yyextra->outputXRef);
3033     //printf("%s: text +=%s\n",listName,qPrint(item->text));
3034   }
3035   else // new item
3036   {
3037 
3038     // if we have already an item from the same list type (e.g. a second @todo)
3039     // in the same Entry (i.e. lii!=0) then we reuse its link anchor.
3040     item = refList->add();
3041     //printf("listName=%s item id = %d new yyextra->current=%p\n",listName,item->id(),yyextra->current);
3042     QCString anchorLabel;
3043     anchorLabel.sprintf("_%s%06d",listName.data(),item->id());
3044     item->setText(yyextra->outputXRef);
3045     item->setAnchor(anchorLabel);
3046     yyextra->current->sli.push_back(item);
3047     QCString cmdString;
3048     cmdString.sprintf(" \\xrefitem %s %d.",qPrint(listName),item->id());
3049     if (yyextra->inBody)
3050     {
3051       yyextra->current->inbodyDocs += cmdString;
3052     }
3053     else
3054     {
3055       yyextra->current->doc += cmdString;
3056     }
3057 
3058     {
3059       SectionManager &sm = SectionManager::instance();
3060       const SectionInfo *si = sm.find(anchorLabel);
3061       if (si)
3062       {
3063         if (!si->ref().isEmpty()) // we are from a tag file
3064         {
3065           si = sm.replace(anchorLabel,listName,yyextra->lineNr,
3066               yyextra->sectionTitle,SectionType::Anchor,
3067               yyextra->sectionLevel);
3068           yyextra->current->anchors.push_back(si);
3069         }
3070         else if (si->lineNr() != -1)
3071         {
3072           warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s, line %d)",qPrint(anchorLabel),qPrint(si->fileName()),si->lineNr());
3073         }
3074         else
3075         {
3076           warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s)",qPrint(anchorLabel),qPrint(si->fileName()));
3077         }
3078       }
3079       else
3080       {
3081         si = sm.add(anchorLabel,listName,yyextra->lineNr,
3082             yyextra->sectionTitle,SectionType::Anchor,
3083             yyextra->sectionLevel);
3084         yyextra->current->anchors.push_back(si);
3085       }
3086     }
3087   }
3088   yyextra->outputXRef.resize(0);
3089 }
3090 
3091 //-----------------------------------------------------------------------------
3092 
3093 // Adds a formula text to the list/dictionary of formulas if it was
3094 // not already added. Returns the label of the formula.
3095 static QCString addFormula(yyscan_t yyscanner)
3096 {
3097   std::unique_lock<std::mutex> lock(g_formulaMutex);
3098   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3099   QCString formLabel;
3100   QCString fText=yyextra->formulaText.simplifyWhiteSpace();
3101   int id = FormulaManager::instance().addFormula(fText.str());
3102   formLabel.sprintf("\\_form#%d",id);
3103   for (int i=0;i<yyextra->formulaNewLines;i++) formLabel+="@_fakenl"; // add fake newlines to
3104                                                          // keep the warnings
3105                                                          // correctly aligned.
3106   return formLabel;
3107 }
3108 
3109 //-----------------------------------------------------------------------------
3110 
3111 static SectionType sectionLevelToType(int level)
3112 {
3113   if (level>=0 && level<5) return (SectionType)level;
3114   return SectionType::Anchor;
3115 }
3116 
3117 static void addSection(yyscan_t yyscanner)
3118 {
3119   std::unique_lock<std::mutex> lock(g_sectionMutex);
3120   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3121   SectionManager &sm = SectionManager::instance();
3122   const SectionInfo *si = sm.find(yyextra->sectionLabel);
3123   if (si)
3124   {
3125     if (!si->ref().isEmpty()) // we are from a tag file
3126     {
3127       // create a new section element
3128       yyextra->sectionTitle+=yytext;
3129       yyextra->sectionTitle=yyextra->sectionTitle.stripWhiteSpace();
3130       si = sm.replace(yyextra->sectionLabel,yyextra->fileName,yyextra->lineNr,
3131                       yyextra->sectionTitle,sectionLevelToType(yyextra->sectionLevel),
3132                       yyextra->sectionLevel);
3133 
3134       // add section to this entry
3135       yyextra->current->anchors.push_back(si);
3136     }
3137     else if (si->lineNr() != -1)
3138     {
3139       warn(yyextra->fileName,yyextra->lineNr,"multiple use of section label '%s' while adding section, (first occurrence: %s, line %d)",qPrint(yyextra->sectionLabel),qPrint(si->fileName()),si->lineNr());
3140     }
3141     else
3142     {
3143       warn(yyextra->fileName,yyextra->lineNr,"multiple use of section label '%s' while adding section, (first occurrence: %s)",qPrint(yyextra->sectionLabel),qPrint(si->fileName()));
3144     }
3145   }
3146   else
3147   {
3148     // create a new section element
3149     yyextra->sectionTitle+=yytext;
3150     yyextra->sectionTitle=yyextra->sectionTitle.stripWhiteSpace();
3151     si = sm.add(yyextra->sectionLabel,yyextra->fileName,yyextra->lineNr,
3152                 yyextra->sectionTitle,sectionLevelToType(yyextra->sectionLevel),
3153                 yyextra->sectionLevel);
3154 
3155     // add section to this entry
3156     yyextra->current->anchors.push_back(si);
3157   }
3158 }
3159 
3160 //-----------------------------------------------------------------------------
3161 
3162 static void addCite(yyscan_t yyscanner)
3163 {
3164   std::unique_lock<std::mutex> lock(g_citeMutex);
3165   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3166   QCString name(yytext);
3167   if (yytext[0] =='"')
3168   {
3169     name=yytext+1;
3170     name=name.left((int)yyleng-2);
3171   }
3172   CitationManager::instance().insert(name);
3173 }
3174 
3175 //-----------------------------------------------------------------------------
3176 
3177 // strip trailing whitespace (excluding newlines) from string s
3178 static void stripTrailingWhiteSpace(QCString &s)
3179 {
3180   uint len = s.length();
3181   int i = (int)len-1;
3182   char c;
3183   while (i>=0)
3184   {
3185     c = s.at(i);
3186     if (c==' ' || c=='\t' || c=='\r') // normal whitespace
3187     {
3188       i--;
3189     }
3190     else if (c=='r' && i>=7 && qstrncmp("\\ilinebr",s.data()+i-7,8)==0) // special line break marker
3191     {
3192       i-=8;
3193     }
3194     else // non-whitespace
3195     {
3196       break;
3197     }
3198   }
3199   //printf("stripTrailingWhitespace(%s) i=%d len=%d\n",qPrint(s),i,len);
3200   if (i!=(int)len-1)
3201   {
3202     s.resize(i+2); // string up to and including char at pos i and \0 terminator
3203   }
3204 }
3205 
3206 // selects the output to write to
3207 static inline void setOutput(yyscan_t yyscanner,OutputContext ctx)
3208 {
3209   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3210   bool xrefAppendToPrev = yyextra->xrefAppendFlag;
3211   // determine append flag for the next item (i.e. the end of this item)
3212   yyextra->xrefAppendFlag = !yyextra->inBody &&
3213                    yyextra->inContext==OutputXRef && ctx==OutputXRef && // two consecutive xref items
3214                    yyextra->newXRefKind==yyextra->xrefKind &&                    // of the same kind
3215                    (yyextra->xrefKind!=XRef_Item ||
3216                     yyextra->newXRefItemKey==yyextra->xrefItemKey);              // with the same key if \xrefitem
3217   //printf("%d && %d && %d && (%d || %d)\n",
3218   //                 yyextra->inContext==OutputXRef,
3219   //                 ctx==OutputXRef,
3220   //                 yyextra->newXRefKind==yyextra->xrefKind,
3221   //                 yyextra->xrefKind!=XRef_Item,
3222   //                 yyextra->newXRefItemKey==yyextra->xrefItemKey);
3223   //printf("refKind=%d yyextra->newXRefKind=%d xrefAppendToPrev=%d yyextra->xrefAppendFlag=%d\n",
3224   //             yyextra->xrefKind,yyextra->newXRefKind,xrefAppendToPrev,yyextra->xrefAppendFlag);
3225 
3226   //printf("setOutput(yyscanner,yyextra->inContext=%d ctx=%d)\n",yyextra->inContext,ctx);
3227   if (yyextra->inContext==OutputXRef) // end of XRef section => add the item
3228   {
3229     // See if we can append this new xref item to the previous one.
3230     // We know this at the start of the next item of the same
3231     // type and need to remember this until the end of that item.
3232     switch(yyextra->xrefKind)
3233     {
3234       case XRef_Todo:
3235         addXRefItem(yyscanner,QCString("todo"),
3236             theTranslator->trTodo(),
3237             theTranslator->trTodoList(),
3238             xrefAppendToPrev
3239             );
3240         break;
3241       case XRef_Test:
3242         addXRefItem(yyscanner,QCString("test"),
3243             theTranslator->trTest(),
3244             theTranslator->trTestList(),
3245             xrefAppendToPrev
3246             );
3247         break;
3248       case XRef_Bug:
3249         addXRefItem(yyscanner,QCString("bug"),
3250             theTranslator->trBug(),
3251             theTranslator->trBugList(),
3252             xrefAppendToPrev
3253             );
3254         break;
3255       case XRef_Deprecated:
3256         addXRefItem(yyscanner,QCString("deprecated"),
3257             theTranslator->trDeprecated(),
3258             theTranslator->trDeprecatedList(),
3259             xrefAppendToPrev
3260             );
3261         break;
3262       case XRef_Item:  // user defined list
3263         addXRefItem(yyscanner,yyextra->xrefItemKey,
3264             yyextra->xrefItemTitle,
3265             yyextra->xrefListTitle,
3266             xrefAppendToPrev
3267             );
3268         break;
3269       case XRef_None:
3270         ASSERT(0);
3271         break;
3272     }
3273   }
3274   yyextra->xrefItemKey = yyextra->newXRefItemKey;
3275 
3276   int oldContext = yyextra->inContext;
3277   yyextra->inContext = ctx;
3278   if (yyextra->inContext!=OutputXRef && yyextra->inBody) yyextra->inContext=OutputInbody;
3279   switch(yyextra->inContext)
3280   {
3281     case OutputDoc:
3282       if (oldContext!=yyextra->inContext)
3283       {
3284         stripTrailingWhiteSpace(yyextra->current->doc);
3285         if (yyextra->current->doc.isEmpty()) yyextra->current->docLine = yyextra->lineNr;
3286         if (yyextra->current->docFile.isEmpty())
3287         {
3288           yyextra->current->docFile = yyextra->fileName;
3289           yyextra->current->docLine = yyextra->lineNr;
3290         }
3291       }
3292       yyextra->pOutputString = &yyextra->current->doc;
3293       break;
3294     case OutputBrief:
3295       if (oldContext!=yyextra->inContext)
3296       {
3297         if (yyextra->current->brief.isEmpty()) yyextra->current->briefLine = yyextra->lineNr;
3298         if (yyextra->current->briefFile.isEmpty())
3299         {
3300           yyextra->current->briefFile = yyextra->fileName;
3301           yyextra->current->briefLine = yyextra->lineNr;
3302         }
3303       }
3304       if (yyextra->current->brief.stripWhiteSpace().isEmpty()) // we only want one brief
3305         // description even if multiple
3306         // are given...
3307       {
3308         yyextra->pOutputString = &yyextra->current->brief;
3309       }
3310       else
3311       {
3312         if (!yyextra->current->doc.isEmpty()) // when appending parts add a new line
3313         {
3314           yyextra->current->doc += "\n";
3315         }
3316         yyextra->pOutputString = &yyextra->current->doc;
3317         yyextra->inContext = OutputDoc; // need to switch to detailed docs, see bug 631380
3318       }
3319       break;
3320     case OutputXRef:
3321       yyextra->pOutputString = &yyextra->outputXRef;
3322       // first item found, so can't append to previous
3323       //yyextra->xrefAppendFlag = FALSE;
3324       break;
3325     case OutputInbody:
3326       yyextra->pOutputString = &yyextra->current->inbodyDocs;
3327       break;
3328   }
3329 }
3330 
3331 
3332 static void addAnchor(yyscan_t yyscanner,const QCString &anchor)
3333 {
3334   std::unique_lock<std::mutex> lock(g_sectionMutex);
3335   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3336   SectionManager &sm = SectionManager::instance();
3337   const SectionInfo *si = sm.find(anchor);
3338   if (si)
3339   {
3340     if (!si->ref().isEmpty()) // we are from a tag file
3341     {
3342       si = sm.replace(anchor,yyextra->fileName,yyextra->lineNr,QCString(),SectionType::Anchor,0);
3343       yyextra->current->anchors.push_back(si);
3344     }
3345     else if (si->lineNr() != -1)
3346     {
3347       warn(yyextra->fileName,yyextra->lineNr,
3348           "multiple use of section label '%s' while adding anchor, (first occurrence: %s, line %d)",
3349           qPrint(anchor),qPrint(si->fileName()),si->lineNr());
3350     }
3351     else
3352     {
3353       warn(yyextra->fileName,yyextra->lineNr,"multiple use of section label '%s' while adding anchor, (first occurrence: %s)",
3354           qPrint(anchor),qPrint(si->fileName()));
3355     }
3356   }
3357   else
3358   {
3359     si = sm.add(anchor,yyextra->fileName,yyextra->lineNr,QCString(),SectionType::Anchor,0);
3360     yyextra->current->anchors.push_back(si);
3361   }
3362 }
3363 
3364 // add a string to the output
3365 static inline void addOutput(yyscan_t yyscanner,const char *s)
3366 {
3367   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3368   //printf("addOutput(yyscanner,%s)\n",s);
3369   *yyextra->pOutputString+=s;
3370 }
3371 
3372 // add a string to the output
3373 static inline void addOutput(yyscan_t yyscanner,const QCString &s)
3374 {
3375   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3376   //printf("addOutput(yyscanner,%s)\n",s);
3377   *yyextra->pOutputString+=s;
3378 }
3379 
3380 // add a character to the output
3381 static inline void addOutput(yyscan_t yyscanner,char c)
3382 {
3383   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3384   *yyextra->pOutputString+=c;
3385 }
3386 
3387 static void addIline(yyscan_t yyscanner,int lineNr)
3388 {
3389   char cmd[30];
3390   sprintf(cmd,"\\iline %d \\ilinebr ",lineNr);
3391   addOutput(yyscanner, cmd);
3392 }
3393 
3394 static void endBrief(yyscan_t yyscanner,bool addToOutput)
3395 {
3396   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3397   if (!yyextra->current->brief.stripWhiteSpace().isEmpty())
3398   { // only go to the detailed description if we have
3399     // found some brief description and not just whitespace
3400     yyextra->briefEndsAtDot=FALSE;
3401     setOutput(yyscanner,OutputDoc);
3402     if (addToOutput) addOutput(yyscanner,yytext);
3403   }
3404 }
3405 
3406 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
3407 {
3408   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3409   yyextra->prevPosition=yyextra->inputPosition;
3410   yy_size_t c=0;
3411   while( c < max_size && yyextra->inputString[yyextra->inputPosition] )
3412   {
3413     *buf = yyextra->inputString[yyextra->inputPosition++] ;
3414     //printf("%d (%c)\n",*buf,*buf);
3415     c++; buf++;
3416   }
3417   return c;
3418 }
3419 
3420 //----------------------------------------------------------------------------
3421 
3422 static void checkFormula(yyscan_t yyscanner)
3423 {
3424   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3425   if (YY_START==ReadFormulaShort || YY_START==ReadFormulaRound || YY_START==ReadFormulaLong)
3426   {
3427     warn(yyextra->fileName,yyextra->lineNr,"End of comment block while inside formula.");
3428   }
3429 }
3430 
3431 //----------------------------------------------------------------------------
3432 
3433 struct CommentScanner::Private
3434 {
3435   yyscan_t yyscanner;
3436   commentscanYY_state extra;
3437 };
3438 
3439 CommentScanner::CommentScanner() : p(std::make_unique<Private>())
3440 {
3441   commentscanYYlex_init_extra(&p->extra,&p->yyscanner);
3442 #ifdef FLEX_DEBUG
3443   commentscanYYset_debug(1,p->yyscanner);
3444 #endif
3445 }
3446 
3447 CommentScanner::~CommentScanner()
3448 {
3449   commentscanYYlex_destroy(p->yyscanner);
3450 }
3451 
3452 bool CommentScanner::parseCommentBlock(/* in */     OutlineParserInterface *parser,
3453                        /* in */     Entry *curEntry,
3454                        /* in */     const QCString &comment,
3455                        /* in */     const QCString &fileName,
3456                        /* in,out */ int  &lineNr,
3457                        /* in */     bool isBrief,
3458                        /* in */     bool isAutoBriefOn,
3459                        /* in */     bool isInbody,
3460                        /* in,out */ Protection &prot,
3461                        /* in,out */ int &position,
3462                        /* out */    bool &newEntryNeeded,
3463                        /* in */     bool markdownSupport
3464                       )
3465 {
3466   yyscan_t yyscanner = p->yyscanner;
3467   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3468   //printf("parseCommentBlock() isBrief=%d isAutoBriefOn=%d lineNr=%d\n",
3469   //    isBrief,isAutoBriefOn,lineNr);
3470 
3471   initParser(yyscanner);
3472   yyextra->guards = std::stack<GuardedSection>();
3473   yyextra->langParser     = parser;
3474   yyextra->current        = curEntry;
3475   yyextra->current->docLine = (lineNr > 1 ? lineNr : 1);
3476   if (comment.isEmpty()) return FALSE; // avoid empty strings
3477   yyextra->inputString    = comment;
3478   yyextra->inputString.append(" ");
3479   yyextra->inputPosition  = position;
3480   yyextra->lineNr         = lineNr;
3481   yyextra->fileName       = fileName;
3482   yyextra->protection     = prot;
3483   yyextra->needNewEntry   = FALSE;
3484   yyextra->xrefKind       = XRef_None;
3485   yyextra->xrefAppendFlag = FALSE;
3486   yyextra->insidePre      = FALSE;
3487   yyextra->parseMore      = FALSE;
3488   yyextra->inBody         = isInbody;
3489   yyextra->markdownSupport= markdownSupport;
3490   yyextra->outputXRef.resize(0);
3491   if (!isBrief && !isAutoBriefOn && !yyextra->current->doc.isEmpty())
3492   { // add newline separator between detailed comment blocks
3493     yyextra->current->doc += '\n';
3494   }
3495   setOutput(yyscanner, isBrief || isAutoBriefOn ? OutputBrief : OutputDoc );
3496   yyextra->briefEndsAtDot = isAutoBriefOn;
3497   yyextra->condCount    = 0;
3498   yyextra->sectionLevel = 0;
3499   yyextra->spaceBeforeCmd.resize(0);
3500   yyextra->spaceBeforeIf.resize(0);
3501 
3502   printlex(yy_flex_debug, TRUE, __FILE__, !fileName.isEmpty() ? qPrint(fileName): NULL);
3503   if (!yyextra->current->inbodyDocs.isEmpty() && isInbody) // separate in body fragments
3504   {
3505     yyextra->current->inbodyDocs+="\n\n";
3506   }
3507 
3508   Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\n"
3509                "input=[\n%s]\n",qPrint(fileName),lineNr,qPrint(yyextra->inputString)
3510               );
3511 
3512   commentscanYYrestart( 0, yyscanner );
3513   BEGIN( Comment );
3514   commentscanYYlex(yyscanner);
3515   setOutput(yyscanner, OutputDoc );
3516 
3517   if (YY_START==OverloadParam) // comment ended with \overload
3518   {
3519     addOutput(yyscanner,getOverloadDocs());
3520   }
3521 
3522   if (!yyextra->guards.empty())
3523   {
3524     warn(yyextra->fileName,yyextra->lineNr,"Documentation block ended in the middle of a conditional section!");
3525   }
3526 
3527   if (yyextra->insideParBlock)
3528   {
3529     warn(yyextra->fileName,yyextra->lineNr,
3530         "Documentation block ended while inside a \\parblock. Missing \\endparblock");
3531   }
3532 
3533   yyextra->current->doc=stripLeadingAndTrailingEmptyLines(yyextra->current->doc,yyextra->current->docLine);
3534 
3535   if (yyextra->current->section==Entry::FILEDOC_SEC && yyextra->current->doc.isEmpty())
3536   {
3537     // to allow a comment block with just a @file command.
3538     yyextra->current->doc="\n\n";
3539   }
3540 
3541   if (yyextra->current->section==Entry::MEMBERGRP_SEC &&
3542       yyextra->docGroup.isEmpty()) // @name section but no group started yet
3543   {
3544     yyextra->docGroup.open(yyextra->current,yyextra->fileName,yyextra->lineNr,true);
3545   }
3546 
3547   Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\noutput=[\n"
3548                "brief=[line=%d\n%s]\ndocs=[line=%d\n%s]\ninbody=[line=%d\n%s]\n]\n===========\n",
3549                qPrint(fileName),lineNr,
3550                yyextra->current->briefLine,qPrint(yyextra->current->brief),
3551                yyextra->current->docLine,qPrint(yyextra->current->doc),
3552                yyextra->current->inbodyLine,qPrint(yyextra->current->inbodyDocs)
3553               );
3554 
3555   checkFormula(yyscanner);
3556   prot = yyextra->protection;
3557 
3558   yyextra->docGroup.addDocs(curEntry);
3559 
3560   newEntryNeeded = yyextra->needNewEntry;
3561 
3562   // if we did not proceed during this call, it does not make
3563   // sense to continue, since we get stuck. See bug 567346 for situations
3564   // were this happens
3565   if (yyextra->parseMore && position==yyextra->inputPosition) yyextra->parseMore=FALSE;
3566 
3567   if (yyextra->parseMore) position=yyextra->inputPosition; else position=0;
3568 
3569   lineNr = yyextra->lineNr;
3570   //printf("position=%d yyextra->parseMore=%d newEntryNeeded=%d\n",
3571   //  position,yyextra->parseMore,newEntryNeeded);
3572 
3573   printlex(yy_flex_debug, FALSE, __FILE__, !fileName.isEmpty() ? qPrint(fileName): NULL);
3574   return yyextra->parseMore;
3575 }
3576 
3577 static void handleGuard(yyscan_t yyscanner,const QCString &expr)
3578 {
3579   struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3580   CondParser prs;
3581   bool sectionEnabled=prs.parse(yyextra->fileName,yyextra->lineNr,expr.stripWhiteSpace());
3582   bool parentEnabled = TRUE;
3583   if (!yyextra->guards.empty()) parentEnabled = yyextra->guards.top().isEnabled();
3584   if (parentEnabled)
3585   {
3586     if (
3587         (sectionEnabled && yyextra->guardType==Guard_If) ||
3588         (!sectionEnabled && yyextra->guardType==Guard_IfNot)
3589        ) // section is visible
3590     {
3591       yyextra->guards.push(GuardedSection(TRUE,TRUE));
3592       yyextra->enabledSectionFound=TRUE;
3593       BEGIN( GuardParamEnd );
3594     }
3595     else // section is invisible
3596     {
3597       if (yyextra->guardType!=Guard_Skip)
3598       {
3599         yyextra->guards.push(GuardedSection(FALSE,TRUE));
3600       }
3601       BEGIN( SkipGuardedSection );
3602     }
3603   }
3604   else // invisible because of parent
3605   {
3606     yyextra->guards.push(GuardedSection(FALSE,FALSE));
3607     BEGIN( SkipGuardedSection );
3608   }
3609 }
3610 
3611 void CommentScanner::initGroupInfo(Entry *entry)
3612 {
3613   struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3614   yyextra->docGroup.initGroupInfo(entry);
3615 }
3616 
3617 void CommentScanner::enterFile(const QCString &fileName,int lineNr)
3618 {
3619   struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3620   yyextra->docGroup.enterFile(fileName,lineNr);
3621 }
3622 
3623 void CommentScanner::leaveFile(const QCString &fileName,int lineNr)
3624 {
3625   struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3626   yyextra->docGroup.leaveFile(fileName,lineNr);
3627 }
3628 
3629 void CommentScanner::enterCompound(const QCString &fileName,int lineNr,const QCString &name)
3630 {
3631   struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3632   yyextra->docGroup.enterCompound(fileName,lineNr,name);
3633 }
3634 
3635 void CommentScanner::leaveCompound(const QCString &fileName,int lineNr,const QCString &name)
3636 {
3637   struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3638   yyextra->docGroup.leaveCompound(fileName,lineNr,name);
3639 }
3640 
3641 void CommentScanner::open(Entry *e,const QCString &fileName,int lineNr,bool implicit)
3642 {
3643   struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3644   yyextra->docGroup.open(e,fileName,lineNr,implicit);
3645 }
3646 
3647 void CommentScanner::close(Entry *e,const QCString &fileName,int lineNr,bool foundInline,bool implicit)
3648 {
3649   struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3650   yyextra->docGroup.close(e,fileName,lineNr,foundInline,implicit);
3651 }
3652 
3653 #if USE_STATE2STRING
3654 #include "commentscan.l.h"
3655 #endif
3656