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