Imported Upstream version 1.8.9
[platform/upstream/doxygen.git] / src / commentcnv.l
1 /*****************************************************************************
2  *
3  * 
4  *
5  * Copyright (C) 1997-2014 by Dimitri van Heesch.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation under the terms of the GNU General Public License is hereby 
9  * granted. No representations are made about the suitability of this software 
10  * for any purpose. It is provided "as is" without express or implied warranty.
11  * See the GNU General Public License for more details.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17
18 %{
19
20 #define YY_NEVER_INTERACTIVE 1
21
22   
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include <qstack.h>
27 #include <qregexp.h>
28 #include <qtextstream.h>
29 #include <qglobal.h>
30
31 #include "bufstr.h"
32 #include "debug.h"
33 #include "message.h"
34 #include "config.h"
35 #include "doxygen.h"
36 #include "util.h"
37 #include "condparser.h"
38
39 #include <assert.h>
40
41 #define YY_NO_INPUT 1
42
43 #define ADDCHAR(c)    g_outBuf->addChar(c)
44 #define ADDARRAY(a,s) g_outBuf->addArray(a,s)
45   
46 struct CondCtx
47 {
48   CondCtx(int line,QCString id,bool b) 
49     : lineNr(line),sectionId(id), skip(b) {}
50   int lineNr;
51   QCString sectionId;
52   bool skip;
53 };
54   
55 struct CommentCtx
56 {
57   CommentCtx(int line) 
58     : lineNr(line) {}
59   int lineNr;
60 };
61   
62 static BufStr * g_inBuf;
63 static BufStr * g_outBuf;
64 static int      g_inBufPos;
65 static int      g_col;
66 static int      g_blockHeadCol;
67 static bool     g_mlBrief;
68 static int      g_readLineCtx;
69 static bool     g_skip;
70 static QCString g_fileName;
71 static int      g_lineNr;
72 static int      g_condCtx;
73 static QStack<CondCtx> g_condStack;
74 static QStack<CommentCtx> g_commentStack;
75 static QCString g_blockName;
76 static int      g_lastCommentContext;
77 static bool     g_inSpecialComment;
78 static bool     g_inRoseComment;
79 static int      g_stringContext;
80 static int      g_charContext;
81 static int      g_javaBlock;
82 static bool     g_specialComment;
83
84 static QCString g_aliasString;
85 static int      g_blockCount;
86 static bool     g_lastEscaped;
87 static int      g_lastBlockContext;
88 static bool     g_pythonDocString;
89 static int      g_nestingCount;
90
91 static SrcLangExt g_lang;
92 static bool       isFixedForm; // For Fortran
93
94 static void replaceCommentMarker(const char *s,int len)
95 {
96   const char *p=s;
97   char c;
98   // copy leading blanks
99   while ((c=*p) && (c==' ' || c=='\t' || c=='\n')) 
100   {
101     ADDCHAR(c);
102     g_lineNr += c=='\n';
103     p++;
104   }
105   // replace start of comment marker by blanks and the last character by a *
106   int blanks=0;
107   while ((c=*p) && (c=='/' || c=='!' || c=='#')) 
108   {
109     blanks++;
110     p++;
111     if (*p=='<') // comment-after-item marker 
112     { 
113       blanks++;
114       p++; 
115     }
116     if (c=='!') // end after first !
117     {
118       break;
119     }
120   }
121   if (blanks>0)
122   {
123     while (blanks>2)
124     {
125       ADDCHAR(' ');
126       blanks--;
127     }
128     if (blanks>1) ADDCHAR('*');
129     ADDCHAR(' ');
130   }
131   // copy comment line to output
132   ADDARRAY(p,len-(int)(p-s));
133 }
134
135 static inline int computeIndent(const char *s)
136 {
137   int col=0;
138   static int tabSize=Config_getInt("TAB_SIZE");
139   const char *p=s;
140   char c;
141   while ((c=*p++))
142   {
143     if (c==' ') col++;
144     else if (c=='\t') col+=tabSize-(col%tabSize); 
145     else break;
146   }
147   return col;
148 }
149
150 static inline void copyToOutput(const char *s,int len)
151 {
152   int i;
153   if (g_skip) // only add newlines.
154   {
155     for (i=0;i<len;i++) 
156     {
157       if (s[i]=='\n') 
158       {
159         ADDCHAR('\n');
160         //fprintf(stderr,"---> skip %d\n",g_lineNr);
161         g_lineNr++;
162       }
163     }
164   }
165   else if (len>0)
166   {
167     ADDARRAY(s,len);
168     static int tabSize=Config_getInt("TAB_SIZE");
169     for (i=0;i<len;i++) 
170     {
171       switch (s[i])
172       {
173         case '\n': g_col=0; 
174                    //fprintf(stderr,"---> copy %d\n",g_lineNr);
175                    g_lineNr++; break;
176         case '\t': g_col+=tabSize-(g_col%tabSize); break;
177         default:   g_col++; break;
178       }
179     }
180   }
181 }
182
183 static void startCondSection(const char *sectId)
184 {
185   //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
186   CondParser prs;
187   bool expResult = prs.parse(g_fileName,g_lineNr,sectId);
188   g_condStack.push(new CondCtx(g_lineNr,sectId,g_skip));
189   if (!expResult) // not enabled
190   {
191     g_skip=TRUE;
192   }
193 }
194
195 static void endCondSection()
196 {
197   if (g_condStack.isEmpty())
198   {
199     warn(g_fileName,g_lineNr,"Found \\endcond command without matching \\cond");
200     g_skip=FALSE;
201   }
202   else
203   {
204     CondCtx *ctx = g_condStack.pop();
205     g_skip=ctx->skip;
206   }
207   //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
208 }
209
210 /** copies string \a s with length \a len to the output, while 
211  *  replacing any alias commands found in the string.
212  */
213 static void replaceAliases(const char *s)
214 {
215   QCString result = resolveAliasCmd(s);
216   //printf("replaceAliases(%s)->'%s'\n",s,result.data());
217   copyToOutput(result,result.length());
218 }
219
220
221 #undef  YY_INPUT
222 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
223
224 static int yyread(char *buf,int max_size)
225 {
226   int bytesInBuf = g_inBuf->curPos()-g_inBufPos;
227   int bytesToCopy = QMIN(max_size,bytesInBuf);
228   memcpy(buf,g_inBuf->data()+g_inBufPos,bytesToCopy);
229   g_inBufPos+=bytesToCopy;
230   return bytesToCopy;
231 }
232
233 void replaceComment(int offset);
234
235 %}
236
237 %option noyywrap
238
239 %x Scan
240 %x SkipString
241 %x SkipChar
242 %x SComment
243 %x CComment
244 %x Verbatim
245 %x VerbatimCode
246 %x ReadLine
247 %x CondLine
248 %x ReadAliasArgs
249
250 %%
251
252 <Scan>[^"'!\/\n\\#-,]*              { /* eat anything that is not " / , or \n */ 
253                                        copyToOutput(yytext,(int)yyleng);
254                                     }
255 <Scan>[,]                           { /* eat , so we have a nice separator in long initialization lines */ 
256                                        copyToOutput(yytext,(int)yyleng);
257                                     }
258 <Scan>"\"\"\""!                     { /* start of python long comment */
259                                      if (g_lang!=SrcLangExt_Python)
260                                      {
261                                        REJECT;
262                                      }
263                                      else
264                                      {
265                                        g_pythonDocString = TRUE;
266                                        g_nestingCount=0;
267                                        g_commentStack.clear(); /*  to be on the save side */
268                                        copyToOutput(yytext,(int)yyleng);
269                                        BEGIN(CComment);
270                                        g_commentStack.push(new CommentCtx(g_lineNr));
271                                      }
272                                    }
273 <Scan>![><!]/.*\n          {
274                                      if (g_lang!=SrcLangExt_Fortran)
275                                      {
276                                        REJECT;
277                                      }
278                                      else
279                                      {
280                                        copyToOutput(yytext,(int)yyleng); 
281                                        g_nestingCount=0;
282                                        g_commentStack.clear(); /*  to be on the save side */
283                                        BEGIN(CComment);
284                                        g_commentStack.push(new CommentCtx(g_lineNr));
285                                      }
286                                    }
287 <Scan>[Cc\*][><!]/.*\n     {
288                                      if (g_lang!=SrcLangExt_Fortran)
289                                      {
290                                        REJECT;
291                                      }
292                                      else
293                                      {
294                                        /* check for fixed format; we might have some conditional as part of multilene if like C<5 .and. & */
295                                        if (isFixedForm && (g_col == 0))
296                                        {
297                                          copyToOutput(yytext,(int)yyleng); 
298                                          g_nestingCount=0;
299                                          g_commentStack.clear(); /*  to be on the save side */
300                                          BEGIN(CComment);
301                                          g_commentStack.push(new CommentCtx(g_lineNr));
302                                        }
303                                        else
304                                        {
305                                          REJECT;
306                                        }
307                                      }
308                                    }
309 <Scan>!.*\n                {
310                                      if (g_lang!=SrcLangExt_Fortran)
311                                      {
312                                        REJECT;
313                                      }
314                                      else
315                                      {
316                                        copyToOutput(yytext,(int)yyleng); 
317                                      }
318                                    }
319 <Scan>[Cc\*].*\n                   {
320                                      if (g_lang!=SrcLangExt_Fortran)
321                                      {
322                                        REJECT;
323                                      }
324                                      else
325                                      {
326                                        if (g_col == 0)
327                                        {
328                                          copyToOutput(yytext,(int)yyleng); 
329                                        }
330                                        else
331                                        {
332                                          REJECT;
333                                        }
334                                      }
335                                    }
336 <Scan>"\""                         { /* start of a string */ 
337                                      copyToOutput(yytext,(int)yyleng); 
338                                      g_stringContext = YY_START;
339                                      BEGIN(SkipString); 
340                                    }
341 <Scan>'                            {
342                                      copyToOutput(yytext,(int)yyleng); 
343                                      g_charContext = YY_START;
344                                      if (g_lang!=SrcLangExt_VHDL)
345                                      {
346                                        BEGIN(SkipChar);
347                                      }
348                                    }
349 <Scan>\n                           { /* new line */ 
350                                      copyToOutput(yytext,(int)yyleng); 
351                                    }
352 <Scan>"//!"/.*\n[ \t]*"//"[\/!][^\/] | /* start C++ style special comment block */
353 <Scan>("///"[/]*)/[^/].*\n[ \t]*"//"[\/!][^\/] { /* start C++ style special comment block */
354                                      if (g_mlBrief) 
355                                      {
356                                        REJECT; // bail out if we do not need to convert
357                                      }
358                                      else
359                                      {
360                                        int i=3;
361                                        if (yytext[2]=='/')
362                                        {
363                                          while (i<(int)yyleng && yytext[i]=='/') i++;
364                                        }
365                                        g_blockHeadCol=g_col;
366                                        copyToOutput("/**",3); 
367                                        replaceAliases(yytext+i);
368                                        g_inSpecialComment=TRUE;
369                                        //BEGIN(SComment); 
370                                        g_readLineCtx=SComment;
371                                        BEGIN(ReadLine);
372                                      }
373                                    }
374 <Scan>"//##Documentation".*/\n     { /* Start of Rational Rose ANSI C++ comment block */
375                                      if (g_mlBrief) REJECT;
376                                      int i=17; //=strlen("//##Documentation");
377                                      g_blockHeadCol=g_col;
378                                      copyToOutput("/**",3);
379                                      replaceAliases(yytext+i);
380                                      g_inRoseComment=TRUE;
381                                      BEGIN(SComment);
382                                    }
383 <Scan>"//"/.*\n                    { /* one line C++ comment */ 
384                                      g_inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
385                                      copyToOutput(yytext,(int)yyleng); 
386                                      g_readLineCtx=YY_START;
387                                      BEGIN(ReadLine);
388                                    }
389 <Scan>"/**/"                       { /* avoid matching next rule for empty C comment, see bug 711723 */
390                                      copyToOutput(yytext,(int)yyleng);
391                                    }
392 <Scan>"/*"[*!]?                    { /* start of a C comment */
393                                      g_specialComment=(int)yyleng==3;
394                                      g_nestingCount=0;
395                                      g_commentStack.clear(); /*  to be on the save side */
396                                      copyToOutput(yytext,(int)yyleng); 
397                                      BEGIN(CComment); 
398                                      g_commentStack.push(new CommentCtx(g_lineNr));
399                                    }
400 <Scan>"#"("#")?                    {
401                                      if (g_lang!=SrcLangExt_Python)
402                                      {
403                                        REJECT;
404                                      }
405                                      else
406                                      {
407                                        copyToOutput(yytext,(int)yyleng); 
408                                        g_nestingCount=0;
409                                        g_commentStack.clear(); /*  to be on the save side */
410                                        BEGIN(CComment);
411                                        g_commentStack.push(new CommentCtx(g_lineNr));
412                                      }
413                                    }
414 <Scan>"--!"                        {
415                                      if (g_lang!=SrcLangExt_VHDL)
416                                      {
417                                        REJECT;
418                                      }
419                                      else
420                                      {
421                                        copyToOutput(yytext,(int)yyleng); 
422                                        g_nestingCount=0;
423                                        g_commentStack.clear(); /*  to be on the save side */
424                                        BEGIN(CComment);
425                                        g_commentStack.push(new CommentCtx(g_lineNr));
426                                      }
427                                    }
428 <Scan>![><!]                       {
429                                      if (g_lang!=SrcLangExt_Fortran)
430                                      {
431                                        REJECT;
432                                      }
433                                      else
434                                      {
435                                        copyToOutput(yytext,(int)yyleng); 
436                                        g_nestingCount=0;
437                                        g_commentStack.clear(); /*  to be on the save side */
438                                        BEGIN(CComment);
439                                        g_commentStack.push(new CommentCtx(g_lineNr));
440                                      }
441                                    }
442 <CComment>"{@code"/[ \t\n]         {
443                                      copyToOutput("@code",5); 
444                                      g_lastCommentContext = YY_START;
445                                      g_javaBlock=1;
446                                      g_blockName=&yytext[1];
447                                      BEGIN(VerbatimCode);
448                                    }
449 <CComment,ReadLine>[\\@]("dot"|"code"|"msc"|"startuml")/[^a-z_A-Z0-9] { /* start of a verbatim block */
450                                      copyToOutput(yytext,(int)yyleng); 
451                                      g_lastCommentContext = YY_START;
452                                      g_javaBlock=0;
453                                      if (qstrcmp(&yytext[1],"startuml")==0)
454                                      {
455                                        g_blockName="uml";
456                                      }
457                                      else
458                                      {
459                                        g_blockName=&yytext[1];
460                                      }
461                                      BEGIN(VerbatimCode);
462                                    }
463 <CComment,ReadLine>[\\@]("f$"|"f["|"f{"[a-z]*) {
464                                      copyToOutput(yytext,(int)yyleng); 
465                                      g_blockName=&yytext[1];
466                                      if (g_blockName.at(1)=='[')
467                                      {
468                                        g_blockName.at(1)=']';
469                                      }
470                                      else if (g_blockName.at(1)=='{')
471                                      {
472                                        g_blockName.at(1)='}';
473                                      }
474                                      g_lastCommentContext = YY_START;
475                                      BEGIN(Verbatim);
476                                    }
477 <CComment,ReadLine>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly")/[^a-z_A-Z0-9] { /* start of a verbatim block */
478                                      copyToOutput(yytext,(int)yyleng); 
479                                      g_blockName=&yytext[1];
480                                      g_lastCommentContext = YY_START;
481                                      BEGIN(Verbatim);
482                                    }
483 <Scan>.                            { /* any ather character */
484                                      copyToOutput(yytext,(int)yyleng); 
485                                    }
486 <Verbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"docbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}") { /* end of verbatim block */
487                                      copyToOutput(yytext,(int)yyleng);
488                                      if (yytext[1]=='f') // end of formula
489                                      {
490                                        BEGIN(g_lastCommentContext);
491                                      }
492                                      else if (&yytext[4]==g_blockName)
493                                      {
494                                        BEGIN(g_lastCommentContext);
495                                      }
496                                    }
497 <VerbatimCode>"{"                  {
498                                      if (g_javaBlock==0)
499                                      {
500                                        REJECT;
501                                      }
502                                      else
503                                      {
504                                        g_javaBlock++;
505                                        copyToOutput(yytext,(int)yyleng);
506                                      }
507                                    }
508 <VerbatimCode>"}"                  {
509                                      if (g_javaBlock==0)
510                                      {
511                                        REJECT;
512                                      }
513                                      else
514                                      {
515                                        g_javaBlock--;
516                                        if (g_javaBlock==0)
517                                        {
518                                          copyToOutput(" @endcode ",10);
519                                          BEGIN(g_lastCommentContext);
520                                        }
521                                        else
522                                        {
523                                          copyToOutput(yytext,(int)yyleng);
524                                        }
525                                      }
526                                    }
527 <VerbatimCode>[\\@]("enddot"|"endcode"|"endmsc"|"enduml") { /* end of verbatim block */
528                                      copyToOutput(yytext,(int)yyleng);
529                                      if (&yytext[4]==g_blockName)
530                                      {
531                                        BEGIN(g_lastCommentContext);
532                                      }
533                                    }
534 <VerbatimCode>^[ \t]*"//"[\!\/]?   { /* skip leading comments */
535                                      if (!g_inSpecialComment)
536                                      {
537                                        copyToOutput(yytext,(int)yyleng); 
538                                      }
539                                      else
540                                      {
541                                        int l=0;
542                                        while (yytext[l]==' ' || yytext[l]=='\t')
543                                        {
544                                          l++;
545                                        }
546                                        copyToOutput(yytext,l);
547                                        if (yyleng-l==3) // ends with //! or ///
548                                        {
549                                          copyToOutput(" * ",3);
550                                        }
551                                        else // ends with //
552                                        {
553                                          copyToOutput("//",2);
554                                        }
555                                      }
556                                    }
557 <Verbatim,VerbatimCode>[^@\/\\\n{}]* { /* any character not a backslash or new line or } */
558                                      copyToOutput(yytext,(int)yyleng); 
559                                    }
560 <Verbatim,VerbatimCode>\n          { /* new line in verbatim block */
561                                      copyToOutput(yytext,(int)yyleng); 
562                                    }
563 <Verbatim>^[ \t]*"///"             {
564                                      if (g_blockName=="dot" || g_blockName=="msc" || g_blockName=="uml" || g_blockName.at(0)=='f')
565                                      {
566                                        // see bug 487871, strip /// from dot images and formulas.
567                                        int l=0;
568                                        while (yytext[l]==' ' || yytext[l]=='\t')
569                                        {
570                                          l++;
571                                        }
572                                        copyToOutput(yytext,l);
573                                        copyToOutput("   ",3);
574                                      }
575                                      else // even slashes are verbatim (e.g. \verbatim, \code)
576                                      {
577                                        REJECT;
578                                      }
579                                    }
580 <Verbatim,VerbatimCode>.           { /* any other character */
581                                      copyToOutput(yytext,(int)yyleng); 
582                                    }
583 <SkipString>\\.                    { /* escaped character in string */
584                                      copyToOutput(yytext,(int)yyleng); 
585                                    }
586 <SkipString>"\""                   { /* end of string */ 
587                                      copyToOutput(yytext,(int)yyleng); 
588                                      BEGIN(g_stringContext); 
589                                    }
590 <SkipString>.                      { /* any other string character */ 
591                                      copyToOutput(yytext,(int)yyleng); 
592                                    }
593 <SkipString>\n                     { /* new line inside string (illegal for some compilers) */ 
594                                      copyToOutput(yytext,(int)yyleng); 
595                                    }
596 <SkipChar>\\.                      { /* escaped character */
597                                      copyToOutput(yytext,(int)yyleng); 
598                                    }
599 <SkipChar>'                        { /* end of character literal */ 
600                                      copyToOutput(yytext,(int)yyleng); 
601                                      BEGIN(g_charContext);
602                                    }
603 <SkipChar>.                        { /* any other string character */ 
604                                      copyToOutput(yytext,(int)yyleng); 
605                                    }
606 <SkipChar>\n                       { /* new line character */
607                                      copyToOutput(yytext,(int)yyleng); 
608                                    }
609
610 <CComment>[^\\!@*\n{\"\/]*           { /* anything that is not a '*' or command */ 
611                                      copyToOutput(yytext,(int)yyleng); 
612                                    }
613 <CComment>"*"+[^*/\\@\n{\"]*       { /* stars without slashes */
614                                      copyToOutput(yytext,(int)yyleng); 
615                                    }
616 <CComment>"\"\"\""                 { /* end of Python docstring */
617                                      if (g_lang!=SrcLangExt_Python)
618                                      {
619                                        REJECT;
620                                      }
621                                      else
622                                      {
623                                        g_pythonDocString = FALSE;
624                                        copyToOutput(yytext,(int)yyleng);
625                                        BEGIN(Scan);
626                                      }
627                                    }
628 <CComment>\n                       { /* new line in comment */
629                                      copyToOutput(yytext,(int)yyleng); 
630                                      /* in case of Fortran always end of comment */
631                                      if (g_lang==SrcLangExt_Fortran)
632                                      {
633                                        BEGIN(Scan);
634                                      }
635                                    }
636 <CComment>"/"+"*"                  { /* nested C comment */
637                                      g_nestingCount++;
638                                      g_commentStack.push(new CommentCtx(g_lineNr));
639                                      copyToOutput(yytext,(int)yyleng); 
640                                    }
641 <CComment>"*"+"/"                  { /* end of C comment */
642                                      if (g_lang==SrcLangExt_Python)
643                                      {
644                                        REJECT;
645                                      }
646                                      else
647                                      {
648                                        copyToOutput(yytext,(int)yyleng);
649                                        if (g_nestingCount<=0)
650                                        {
651                                          BEGIN(Scan);
652                                        }
653                                        else
654                                        {
655                                          g_nestingCount--;
656                                          delete g_commentStack.pop();
657                                        }
658                                      }
659                                    }
660 <CComment>"\n"/[ \t]*[^#]          { /* end of Python comment */
661                                      if (g_lang!=SrcLangExt_Python || g_pythonDocString)
662                                      {
663                                        REJECT;
664                                      }
665                                      else
666                                      {
667                                        copyToOutput(yytext,(int)yyleng);
668                                        BEGIN(Scan);
669                                      }
670                                    }
671 <CComment>"\n"/[ \t]*[^\-]         { /* end of VHDL comment */
672                                      if (g_lang!=SrcLangExt_VHDL)
673                                      {
674                                        REJECT;
675                                      }
676                                      else
677                                      {
678                                        copyToOutput(yytext,(int)yyleng);
679                                        BEGIN(Scan);
680                                      }
681                                    }
682    /* removed for bug 674842 (bug was introduced in rev 768)
683 <CComment>"'"                      {
684                                      g_charContext = YY_START;
685                                      copyToOutput(yytext,(int)yyleng);
686                                      BEGIN(SkipChar);
687                                    }
688 <CComment>"\""                     {
689                                      g_stringContext = YY_START;
690                                      copyToOutput(yytext,(int)yyleng);
691                                      BEGIN(SkipString);
692                                    }
693    */
694 <CComment>.                        {
695                                      copyToOutput(yytext,(int)yyleng); 
696                                    }
697 <SComment>^[ \t]*"///"[\/]*/\n     {
698                                      replaceComment(0);
699                                    }
700 <SComment>\n[ \t]*"///"[\/]*/\n    {
701                                      replaceComment(1); 
702                                    }
703 <SComment>^[ \t]*"///"[^\/\n]/.*\n { 
704                                      replaceComment(0);
705                                      g_readLineCtx=YY_START;
706                                      BEGIN(ReadLine);
707                                    }
708 <SComment>\n[ \t]*"///"[^\/\n]/.*\n  { 
709                                      replaceComment(1); 
710                                      g_readLineCtx=YY_START;
711                                      BEGIN(ReadLine);
712                                    }
713 <SComment>^[ \t]*"//!"             |    // just //!
714 <SComment>^[ \t]*"//!<"/.*\n       |    // or   //!< something
715 <SComment>^[ \t]*"//!"[^<]/.*\n    {    // or   //!something
716                                      replaceComment(0);
717                                      g_readLineCtx=YY_START;
718                                      BEGIN(ReadLine);
719                                    }
720 <SComment>\n[ \t]*"//!"            |
721 <SComment>\n[ \t]*"//!<"/.*\n      |
722 <SComment>\n[ \t]*"//!"[^<\n]/.*\n { 
723                                      replaceComment(1); 
724                                      g_readLineCtx=YY_START;
725                                      BEGIN(ReadLine);
726                                    }
727 <SComment>^[ \t]*"//##"/.*\n       {
728                                      if (!g_inRoseComment)
729                                      {
730                                        REJECT;
731                                      }
732                                      else
733                                      {
734                                        replaceComment(0);
735                                        g_readLineCtx=YY_START;
736                                        BEGIN(ReadLine);
737                                      }
738                                    }
739 <SComment>\n[ \t]*"//##"/.*\n      {
740                                      if (!g_inRoseComment)
741                                      {
742                                        REJECT;
743                                      }
744                                      else
745                                      {
746                                        replaceComment(1); 
747                                        g_readLineCtx=YY_START;
748                                        BEGIN(ReadLine);
749                                      }
750                                    }
751 <SComment>\n                       { /* end of special comment */
752                                      copyToOutput(" */",3); 
753                                      copyToOutput(yytext,(int)yyleng); 
754                                      g_inSpecialComment=FALSE;
755                                      g_inRoseComment=FALSE;
756                                      BEGIN(Scan); 
757                                    }
758 <ReadLine>[^\\@\n]*/\n             {
759                                      copyToOutput(yytext,(int)yyleng);
760                                      BEGIN(g_readLineCtx);
761                                    }
762 <CComment,ReadLine>[\\@][\\@][~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
763                                      copyToOutput(yytext,(int)yyleng);
764                                    }
765 <CComment,ReadLine>[\\@]"cond"/[^a-z_A-Z0-9]       { // conditional section
766                                      g_condCtx = YY_START; 
767                                      BEGIN(CondLine);
768                                    }
769 <CComment,ReadLine>[\\@]"endcond"/[^a-z_A-Z0-9] { // end of conditional section
770                                      bool oldSkip=g_skip;
771                                      endCondSection();
772                                      if (YY_START==CComment && oldSkip && !g_skip) 
773                                      {
774                                        //printf("** Adding start of comment!\n");
775                                        if (g_lang!=SrcLangExt_Python &&
776                                            g_lang!=SrcLangExt_VHDL &&
777                                            g_lang!=SrcLangExt_Fortran)
778                                        {
779                                          ADDCHAR('/');
780                                          ADDCHAR('*');
781                                          if (g_specialComment)
782                                          {
783                                            ADDCHAR('*');
784                                          }
785                                        }
786                                      }
787                                     }
788 <CondLine>[!()&| \ta-z_A-Z0-9.\-]+ {
789                                      bool oldSkip=g_skip;
790                                      startCondSection(yytext);
791                                      if ((g_condCtx==CComment || g_readLineCtx==SComment) && 
792                                          !oldSkip && g_skip) 
793                                      {
794                                        if (g_lang!=SrcLangExt_Python &&
795                                            g_lang!=SrcLangExt_VHDL &&
796                                            g_lang!=SrcLangExt_Fortran)
797                                        {
798                                          ADDCHAR('*');
799                                          ADDCHAR('/');
800                                        }
801                                      }
802                                      if (g_readLineCtx==SComment)
803                                      {
804                                        BEGIN(SComment);
805                                      }
806                                      else
807                                      {
808                                        BEGIN(g_condCtx);
809                                      }
810                                    }
811 <CondLine>[ \t]*
812 <CComment,ReadLine>[\\@]"cond"[ \t\r]*/\n |
813 <CondLine>.                        { // forgot section id?
814                                      if (YY_START!=CondLine) g_condCtx=YY_START;
815                                      bool oldSkip=g_skip;
816                                      startCondSection(" "); // fake section id causing the section to be hidden unconditionally
817                                      if ((g_condCtx==CComment || g_readLineCtx==SComment) && 
818                                          !oldSkip && g_skip) 
819                                      {
820                                        //printf("** Adding terminator for comment!\n");
821                                        if (g_lang!=SrcLangExt_Python &&
822                                            g_lang!=SrcLangExt_VHDL)
823                                        {
824                                          ADDCHAR('*');
825                                          ADDCHAR('/');
826                                        }
827                                      }
828                                      if (*yytext=='\n') g_lineNr++;
829                                      if (g_readLineCtx==SComment)
830                                      {
831                                        BEGIN(SComment);
832                                      }
833                                      else
834                                      {
835                                        BEGIN(g_condCtx);
836                                      }
837                                    }
838 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]*  { // expand alias without arguments
839                                      replaceAliases(yytext);
840                                    }
841 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]*"{" { // expand alias with arguments
842                                      g_lastBlockContext=YY_START;
843                                      g_blockCount=1;
844                                      g_aliasString=yytext;
845                                      g_lastEscaped=0;
846                                      BEGIN( ReadAliasArgs );
847                                    }
848 <ReadAliasArgs>^[ \t]*"//"[/!]/[^\n]+   { // skip leading special comments (see bug 618079)
849                                    }
850 <ReadAliasArgs>"*/"                { // oops, end of comment in the middle of an alias?
851                                      if (g_lang==SrcLangExt_Python)
852                                      {
853                                        REJECT;
854                                      }
855                                      else // abort the alias, restart scanning
856                                      {
857                                        copyToOutput(g_aliasString,g_aliasString.length());
858                                        copyToOutput(yytext,(int)yyleng);
859                                        BEGIN(Scan);
860                                      }
861                                    }
862 <ReadAliasArgs>[^{}\n\\\*]+        {
863                                      g_aliasString+=yytext;
864                                      g_lastEscaped=FALSE;
865                                    }
866 <ReadAliasArgs>"\\"                {
867                                      if (g_lastEscaped)  g_lastEscaped=FALSE;
868                                      else                g_lastEscaped=TRUE;
869                                      g_aliasString+=yytext;
870                                    }
871 <ReadAliasArgs>\n                  {
872                                      g_aliasString+=yytext;
873                                      g_lineNr++;
874                                      g_lastEscaped=FALSE;
875                                    }
876 <ReadAliasArgs>"{"                 {
877                                      g_aliasString+=yytext;
878                                      if (!g_lastEscaped) g_blockCount++;
879                                      g_lastEscaped=FALSE;
880                                    }
881 <ReadAliasArgs>"}"                 {
882                                      g_aliasString+=yytext;
883                                      if (!g_lastEscaped) g_blockCount--;
884                                      if (g_blockCount==0)
885                                      {
886                                        replaceAliases(g_aliasString);
887                                        BEGIN( g_lastBlockContext );
888                                      }
889                                      g_lastEscaped=FALSE;
890                                    }
891 <ReadAliasArgs>.                   {
892                                      g_aliasString+=yytext;
893                                      g_lastEscaped=FALSE;
894                                    }
895 <ReadLine>.                        {
896                                      copyToOutput(yytext,(int)yyleng);
897                                    }
898
899 %%
900
901 void replaceComment(int offset)
902 {
903   if (g_mlBrief || g_skip)
904   {
905     copyToOutput(yytext,(int)yyleng);
906   }
907   else
908   {
909     //printf("replaceComment(%s)\n",yytext);
910     int i=computeIndent(&yytext[offset]);
911     if (i==g_blockHeadCol)
912     {
913       replaceCommentMarker(yytext,(int)yyleng);
914     }
915     else
916     {
917       copyToOutput(" */",3);
918       int i;for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
919       g_inSpecialComment=FALSE;
920       BEGIN(Scan);                                            
921     }                                                         
922   }
923 }
924
925 // simplified way to know if this is fixed form
926 // duplicate in fortrancode.l
927 static bool recognizeFixedForm(const char* contents)
928 {
929   int column=0;
930   bool skipLine=FALSE;
931
932   for(int i=0;;i++) {
933     column++;
934
935     switch(contents[i]) {
936       case '\n':
937         column=0;
938         skipLine=FALSE;
939         break;
940       case ' ':
941         break;
942       case '\000':
943         return FALSE;
944       case 'C':
945       case 'c':
946       case '*':
947         if(column==1) return TRUE;
948         if(skipLine) break;
949         return FALSE;
950       case '!':
951         if(column>1 && column<7) return FALSE;
952         skipLine=TRUE;
953         break;
954       default:
955         if(skipLine) break;
956         if(column==7) return TRUE;
957         return FALSE;
958     }
959   }
960   return FALSE;
961 }
962
963
964 /*! This function does three things:
965  *  -# It converts multi-line C++ style comment blocks (that are aligned)
966  *     to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
967  *  -# It replaces aliases with their definition (see ALIASES)
968  *  -# It handles conditional sections (cond...endcond blocks)
969  */
970 void convertCppComments(BufStr *inBuf,BufStr *outBuf,const char *fileName)
971 {
972   //printf("convertCppComments(%s)\n",fileName);
973   g_inBuf    = inBuf;
974   g_outBuf   = outBuf;
975   g_inBufPos = 0;
976   g_col      = 0;
977   g_mlBrief = Config_getBool("MULTILINE_CPP_IS_BRIEF");
978   g_skip     = FALSE;
979   g_fileName = fileName;
980   g_lang = getLanguageFromFileName(fileName);
981   g_pythonDocString = FALSE;
982   g_lineNr   = 1;
983   g_condStack.clear();
984   g_condStack.setAutoDelete(TRUE);
985   g_commentStack.clear();
986   g_commentStack.setAutoDelete(TRUE);
987
988   printlex(yy_flex_debug, TRUE, __FILE__, fileName);
989   isFixedForm = FALSE;
990   if (g_lang==SrcLangExt_Fortran)
991   {
992     isFixedForm = recognizeFixedForm(inBuf->data());
993   }
994
995   if (g_lang==SrcLangExt_Markdown)
996   {
997     g_nestingCount=0;
998     BEGIN(CComment);
999     g_commentStack.push(new CommentCtx(g_lineNr));
1000   }
1001   else
1002   {
1003     BEGIN(Scan);
1004   }
1005   yylex();
1006   while (!g_condStack.isEmpty())
1007   {
1008     CondCtx *ctx = g_condStack.pop();
1009     QCString sectionInfo = " ";
1010     if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label %s ",ctx->sectionId.data()); 
1011     warn(g_fileName,ctx->lineNr,"Conditional section%sdoes not have "
1012         "a corresponding \\endcond command within this file.",sectionInfo.data());
1013   }
1014   if (g_nestingCount>0 && g_lang!=SrcLangExt_Markdown)
1015   {
1016     QCString tmp= "(probable line reference: ";
1017     bool first = TRUE;
1018     while (!g_commentStack.isEmpty())
1019     {
1020       CommentCtx *ctx = g_commentStack.pop();
1021       if (!first) tmp += ", ";
1022       tmp += QCString().setNum(ctx->lineNr);
1023       first = FALSE;
1024       delete ctx;
1025     }
1026     tmp += ")";
1027     warn(g_fileName,g_lineNr,"Reached end of file while still inside a (nested) comment. "
1028         "Nesting level %d %s",g_nestingCount+1,tmp.data()); // add one for "normal" expected end of comment
1029   }
1030   g_commentStack.clear();
1031   if (Debug::isFlagSet(Debug::CommentCnv))
1032   {
1033     g_outBuf->at(g_outBuf->curPos())='\0';
1034     msg("-------------\n%s\n-------------\n",g_outBuf->data());
1035   }
1036   printlex(yy_flex_debug, FALSE, __FILE__, fileName);
1037 }
1038
1039
1040 //----------------------------------------------------------------------------
1041 #if !defined(YY_FLEX_SUBMINOR_VERSION) 
1042 extern "C" { // some bogus code to keep the compiler happy
1043     void commentcnvYYdummy() { yy_flex_realloc(0,0); } 
1044 }
1045 #endif
1046