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