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