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