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