1 /*****************************************************************************
5 * Copyright (C) 1997-2015 by Dimitri van Heesch.
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.
13 * Documents produced by Doxygen are derivative works derived from the
14 * input used in their production; they are not affected by this license.
17 %option never-interactive
18 %option prefix="commentcnvYY"
20 %option extra-type="struct commentcnvYY_state *"
30 #include <qtextstream.h>
39 #include "condparser.h"
44 #define YY_NO_UNISTD_H 1
46 #define ADDCHAR(c) yyextra->outBuf->addChar(c)
47 #define ADDARRAY(a,s) yyextra->outBuf->addArray(a,s)
51 CondCtx(int line,QCString id,bool b)
52 : lineNr(line),sectionId(id), skip(b) {}
65 struct commentcnvYY_state
78 QStack<CondCtx> condStack;
79 QStack<CommentCtx> commentStack;
81 int lastCommentContext = 0;
82 bool inSpecialComment = FALSE;
83 bool inRoseComment= FALSE;
84 int stringContext = 0;
87 bool specialComment = FALSE;
91 bool lastEscaped = FALSE;
92 int lastBlockContext= 0;
93 bool pythonDocString = FALSE;
96 bool vhdl = FALSE; // for VHDL old style --! comment
98 SrcLangExt lang = SrcLangExt_Unknown;
99 bool isFixedForm = FALSE; // For Fortran
102 static const char *stateToString(int state);
103 static inline int computeIndent(const char *s);
105 static void replaceCommentMarker(yyscan_t yyscanner,const char *s,int len);
106 static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len);
107 static void startCondSection(yyscan_t yyscanner,const char *sectId);
108 static void endCondSection(yyscan_t yyscanner);
109 static void handleCondSectionId(yyscan_t yyscanner,const char *expression);
110 static void replaceAliases(yyscan_t yyscanner,const char *s);
111 static int yyread(yyscan_t yyscanner,char *buf,int max_size);
112 static void replaceComment(yyscan_t yyscanner,int offset);
118 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
123 MAILADR ("mailto:")?[a-z_A-Z0-9.+-]+"@"[a-z_A-Z0-9-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
140 <Scan>[^"'!\/\n\\#,\-]* { /* eat anything that is not " / , or \n */
141 copyToOutput(yyscanner,yytext,(int)yyleng);
143 <Scan>[,] { /* eat , so we have a nice separator in long initialization lines */
144 copyToOutput(yyscanner,yytext,(int)yyleng);
146 <Scan>"\"\"\""! { /* start of python long comment */
147 if (yyextra->lang!=SrcLangExt_Python)
153 yyextra->pythonDocString = TRUE;
154 yyextra->nestingCount=1;
155 yyextra->commentStack.clear(); /* to be on the save side */
156 copyToOutput(yyscanner,yytext,(int)yyleng);
158 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
162 if (yyextra->lang!=SrcLangExt_Fortran)
168 copyToOutput(yyscanner,yytext,(int)yyleng);
169 yyextra->nestingCount=0; // Fortran doesn't have an end comment
170 yyextra->commentStack.clear(); /* to be on the save side */
172 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
175 <Scan>[Cc\*][><!]/.*\n {
176 if (yyextra->lang!=SrcLangExt_Fortran)
182 /* check for fixed format; we might have some conditional as part of multiline if like C<5 .and. & */
183 if (yyextra->isFixedForm && (yyextra->col == 0))
185 copyToOutput(yyscanner,yytext,(int)yyleng);
186 yyextra->nestingCount=0; // Fortran doesn't have an end comment
187 yyextra->commentStack.clear(); /* to be on the safe side */
189 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
198 if (yyextra->lang!=SrcLangExt_Fortran)
204 copyToOutput(yyscanner,yytext,(int)yyleng);
208 if (yyextra->lang!=SrcLangExt_Fortran)
214 if (yyextra->col == 0)
216 copyToOutput(yyscanner,yytext,(int)yyleng);
224 <Scan>"\"" { /* start of a string */
225 copyToOutput(yyscanner,yytext,(int)yyleng);
226 yyextra->stringContext = YY_START;
230 copyToOutput(yyscanner,yytext,(int)yyleng);
231 yyextra->charContext = YY_START;
232 if (yyextra->lang!=SrcLangExt_VHDL)
237 <Scan>\n { /* new line */
238 copyToOutput(yyscanner,yytext,(int)yyleng);
240 <Scan>"//!"/.*\n[ \t]*"//"[\/!][^\/] | /* start C++ style special comment block */
241 <Scan>("///"[/]*)/[^/].*\n[ \t]*"//"[\/!][^\/] { /* start C++ style special comment block */
242 if (yyextra->mlBrief)
244 REJECT; // bail out if we do not need to convert
251 while (i<(int)yyleng && yytext[i]=='/') i++;
253 yyextra->blockHeadCol=yyextra->col;
254 copyToOutput(yyscanner,"/**",3);
255 replaceAliases(yyscanner,yytext+i);
256 yyextra->inSpecialComment=TRUE;
258 yyextra->readLineCtx=SComment;
262 <Scan>"//##Documentation".*/\n { /* Start of Rational Rose ANSI C++ comment block */
263 if (yyextra->mlBrief) REJECT;
264 int i=17; //=strlen("//##Documentation");
265 yyextra->blockHeadCol=yyextra->col;
266 copyToOutput(yyscanner,"/**",3);
267 replaceAliases(yyscanner,yytext+i);
268 yyextra->inRoseComment=TRUE;
271 <Scan>"//"[!\/]/.*\n[ \t]*"//"[|\/][ \t]*[@\\]"}" { // next line contains an end marker, see bug 752712
272 yyextra->inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
273 copyToOutput(yyscanner,yytext,(int)yyleng);
274 yyextra->readLineCtx=YY_START;
277 <Scan>"//"/.*\n { /* one line C++ comment */
278 yyextra->inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
279 copyToOutput(yyscanner,yytext,(int)yyleng);
280 yyextra->readLineCtx=YY_START;
283 <Scan>"/**/" { /* avoid matching next rule for empty C comment, see bug 711723 */
284 copyToOutput(yyscanner,yytext,(int)yyleng);
286 <Scan>"/*"[*!]? { /* start of a C comment */
287 if ((yyextra->lang==SrcLangExt_Python) || (yyextra->lang==SrcLangExt_Tcl))
291 yyextra->specialComment=(int)yyleng==3;
292 yyextra->nestingCount=1;
293 yyextra->commentStack.clear(); /* to be on the save side */
294 copyToOutput(yyscanner,yytext,(int)yyleng);
296 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
299 if (yyextra->lang!=SrcLangExt_Python)
305 copyToOutput(yyscanner,yytext,(int)yyleng);
306 yyextra->nestingCount=0; // Python doesn't have an end comment for #
307 yyextra->commentStack.clear(); /* to be on the save side */
309 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
313 if (yyextra->lang!=SrcLangExt_VHDL)
319 yyextra->vhdl = TRUE;
320 copyToOutput(yyscanner,yytext,(int)yyleng);
321 yyextra->nestingCount=0; // VHDL doesn't have an end comment
322 yyextra->commentStack.clear(); /* to be on the save side */
324 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
328 if (yyextra->lang!=SrcLangExt_Fortran)
334 copyToOutput(yyscanner,yytext,(int)yyleng);
335 yyextra->nestingCount=0; // Fortran doesn't have an end comment
336 yyextra->commentStack.clear(); /* to be on the save side */
338 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
341 <CComment,ReadLine>{MAILADR} |
342 <CComment,ReadLine>"<"{MAILADR}">" { // Mail address, to prevent seeing e.g x@code-factory.org as start of a code block
343 copyToOutput(yyscanner,yytext,(int)yyleng);
345 <CComment>"{@code"/[ \t\n] {
346 copyToOutput(yyscanner,"@code",5);
347 yyextra->lastCommentContext = YY_START;
348 yyextra->javaBlock=1;
349 yyextra->blockName=&yytext[1];
352 <CComment,ReadLine>[\\@]("dot"|"code"|"msc"|"startuml")/[^a-z_A-Z0-9] { /* start of a verbatim block */
353 copyToOutput(yyscanner,yytext,(int)yyleng);
354 yyextra->lastCommentContext = YY_START;
355 yyextra->javaBlock=0;
356 if (qstrcmp(&yytext[1],"startuml")==0)
358 yyextra->blockName="uml";
362 yyextra->blockName=&yytext[1];
366 <CComment,ReadLine>[\\@]("f$"|"f["|"f{") {
367 copyToOutput(yyscanner,yytext,(int)yyleng);
368 yyextra->blockName=&yytext[1];
369 if (yyextra->blockName.at(1)=='[')
371 yyextra->blockName.at(1)=']';
373 else if (yyextra->blockName.at(1)=='{')
375 yyextra->blockName.at(1)='}';
377 yyextra->lastCommentContext = YY_START;
380 <CComment,ReadLine>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly")/[^a-z_A-Z0-9] { /* start of a verbatim block */
381 copyToOutput(yyscanner,yytext,(int)yyleng);
382 yyextra->blockName=&yytext[1];
383 yyextra->lastCommentContext = YY_START;
386 <Scan>. { /* any other character */
387 copyToOutput(yyscanner,yytext,(int)yyleng);
389 <Verbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}") { /* end of verbatim block */
390 copyToOutput(yyscanner,yytext,(int)yyleng);
391 if (&yytext[1]==yyextra->blockName) // end of formula
393 BEGIN(yyextra->lastCommentContext);
395 else if (&yytext[4]==yyextra->blockName)
397 BEGIN(yyextra->lastCommentContext);
401 if (yyextra->javaBlock==0)
407 yyextra->javaBlock++;
408 copyToOutput(yyscanner,yytext,(int)yyleng);
412 if (yyextra->javaBlock==0)
418 yyextra->javaBlock--;
419 if (yyextra->javaBlock==0)
421 copyToOutput(yyscanner," @endcode ",10);
422 BEGIN(yyextra->lastCommentContext);
426 copyToOutput(yyscanner,yytext,(int)yyleng);
430 <VerbatimCode>[\\@]("enddot"|"endcode"|"endmsc"|"enduml") { /* end of verbatim block */
431 copyToOutput(yyscanner,yytext,(int)yyleng);
432 if (&yytext[4]==yyextra->blockName)
434 BEGIN(yyextra->lastCommentContext);
437 <VerbatimCode>^[ \t]*"//"[\!\/]? { /* skip leading comments */
438 if (!yyextra->inSpecialComment)
440 copyToOutput(yyscanner,yytext,(int)yyleng);
445 while (yytext[l]==' ' || yytext[l]=='\t')
449 copyToOutput(yyscanner,yytext,l);
450 if (yyleng-l==3) // ends with //! or ///
452 copyToOutput(yyscanner," * ",3);
456 copyToOutput(yyscanner,"//",2);
460 <Verbatim,VerbatimCode>[^@\/\\\n{}]* { /* any character not a backslash or new line or } */
461 copyToOutput(yyscanner,yytext,(int)yyleng);
463 <Verbatim,VerbatimCode>\n { /* new line in verbatim block */
464 copyToOutput(yyscanner,yytext,(int)yyleng);
466 <Verbatim>^[ \t]*"///" {
467 if (yyextra->blockName=="dot" || yyextra->blockName=="msc" || yyextra->blockName=="uml" || yyextra->blockName.at(0)=='f')
469 // see bug 487871, strip /// from dot images and formulas.
471 while (yytext[l]==' ' || yytext[l]=='\t')
475 copyToOutput(yyscanner,yytext,l);
476 copyToOutput(yyscanner," ",3);
478 else // even slashes are verbatim (e.g. \verbatim, \code)
483 <Verbatim,VerbatimCode>. { /* any other character */
484 copyToOutput(yyscanner,yytext,(int)yyleng);
486 <SkipString>\\. { /* escaped character in string */
487 if (yyextra->lang==SrcLangExt_Fortran)
490 copyToOutput(yyscanner,yytext,1);
494 copyToOutput(yyscanner,yytext,(int)yyleng);
497 <SkipString>"\"" { /* end of string */
498 copyToOutput(yyscanner,yytext,(int)yyleng);
499 BEGIN(yyextra->stringContext);
501 <SkipString>. { /* any other string character */
502 copyToOutput(yyscanner,yytext,(int)yyleng);
504 <SkipString>\n { /* new line inside string (illegal for some compilers) */
505 copyToOutput(yyscanner,yytext,(int)yyleng);
507 <SkipChar>\\. { /* escaped character */
508 if (yyextra->lang==SrcLangExt_Fortran)
511 copyToOutput(yyscanner,yytext,1);
515 copyToOutput(yyscanner,yytext,(int)yyleng);
518 <SkipChar>' { /* end of character literal */
519 copyToOutput(yyscanner,yytext,(int)yyleng);
520 BEGIN(yyextra->charContext);
522 <SkipChar>. { /* any other string character */
523 copyToOutput(yyscanner,yytext,(int)yyleng);
525 <SkipChar>\n { /* new line character */
526 copyToOutput(yyscanner,yytext,(int)yyleng);
529 <CComment>[^ <\\!@*\n{\"\/]* { /* anything that is not a '*' or command */
530 copyToOutput(yyscanner,yytext,(int)yyleng);
532 <CComment>"*"+[^*/\\@\n{\"]* { /* stars without slashes */
533 copyToOutput(yyscanner,yytext,(int)yyleng);
535 <CComment>"\"\"\"" { /* end of Python docstring */
536 if (yyextra->lang!=SrcLangExt_Python)
542 yyextra->nestingCount--;
543 yyextra->pythonDocString = FALSE;
544 copyToOutput(yyscanner,yytext,(int)yyleng);
548 <CComment>\n { /* new line in comment */
549 copyToOutput(yyscanner,yytext,(int)yyleng);
550 /* in case of Fortran always end of comment */
551 if (yyextra->lang==SrcLangExt_Fortran)
556 <CComment>"/"+"*" { /* nested C comment */
557 if ((yyextra->lang==SrcLangExt_Python) || (yyextra->lang==SrcLangExt_Tcl))
561 yyextra->nestingCount++;
562 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
563 copyToOutput(yyscanner,yytext,(int)yyleng);
565 <CComment>"*"+"/" { /* end of C comment */
566 if ((yyextra->lang==SrcLangExt_Python) || (yyextra->lang==SrcLangExt_Tcl))
572 copyToOutput(yyscanner,yytext,(int)yyleng);
573 yyextra->nestingCount--;
574 if (yyextra->nestingCount<=0)
580 //yyextra->nestingCount--;
581 delete yyextra->commentStack.pop();
585 /* Python an VHDL share CComment, so special attention for ending comments is required */
586 <CComment>"\n"/[ \t]*"#" {
587 if (yyextra->lang!=SrcLangExt_VHDL)
593 if (yyextra->vhdl) // inside --! comment
595 yyextra->vhdl = FALSE;
596 copyToOutput(yyscanner,yytext,(int)yyleng);
599 else // C-type comment
605 <CComment>"\n"/[ \t]*"-" {
606 if (yyextra->lang!=SrcLangExt_Python || yyextra->pythonDocString)
612 copyToOutput(yyscanner,yytext,(int)yyleng);
616 <CComment>"\n"/[ \t]*[^ \t#\-] {
617 if (yyextra->lang==SrcLangExt_Python)
619 if (yyextra->pythonDocString)
625 copyToOutput(yyscanner,yytext,(int)yyleng);
629 else if (yyextra->lang==SrcLangExt_VHDL)
631 if (yyextra->vhdl) // inside --! comment
633 yyextra->vhdl = FALSE;
634 copyToOutput(yyscanner,yytext,(int)yyleng);
637 else // C-type comment
647 /* removed for bug 674842 (bug was introduced in rev 768)
649 yyextra->charContext = YY_START;
650 copyToOutput(yyscanner,yytext,(int)yyleng);
654 yyextra->stringContext = YY_START;
655 copyToOutput(yyscanner,yytext,(int)yyleng);
660 copyToOutput(yyscanner,yytext,(int)yyleng);
662 <SComment>^[ \t]*"///"[\/]*/\n {
663 replaceComment(yyscanner,0);
665 <SComment>\n[ \t]*"///"[\/]*/\n {
666 replaceComment(yyscanner,1);
668 <SComment>^[ \t]*"///"[^\/\n]/.*\n {
669 replaceComment(yyscanner,0);
670 yyextra->readLineCtx=YY_START;
673 <SComment>\n[ \t]*"//"[\/!]("<")?[ \t]*[\\@]"}".*\n {
674 /* See Bug 752712: end the multiline comment when finding a @} or \} command */
675 copyToOutput(yyscanner," */",3);
676 copyToOutput(yyscanner,yytext,(int)yyleng);
677 yyextra->inSpecialComment=FALSE;
678 yyextra->inRoseComment=FALSE;
681 <SComment>\n[ \t]*"///"[^\/\n]/.*\n {
682 replaceComment(yyscanner,1);
683 yyextra->readLineCtx=YY_START;
686 <SComment>^[ \t]*"//!" | // just //!
687 <SComment>^[ \t]*"//!<"/.*\n | // or //!< something
688 <SComment>^[ \t]*"//!"[^<]/.*\n { // or //!something
689 replaceComment(yyscanner,0);
690 yyextra->readLineCtx=YY_START;
693 <SComment>\n[ \t]*"//!" |
694 <SComment>\n[ \t]*"//!<"/.*\n |
695 <SComment>\n[ \t]*"//!"[^<\n]/.*\n {
696 replaceComment(yyscanner,1);
697 yyextra->readLineCtx=YY_START;
700 <SComment>^[ \t]*"//##"/.*\n {
701 if (!yyextra->inRoseComment)
707 replaceComment(yyscanner,0);
708 yyextra->readLineCtx=YY_START;
712 <SComment>\n[ \t]*"//##"/.*\n {
713 if (!yyextra->inRoseComment)
719 replaceComment(yyscanner,1);
720 yyextra->readLineCtx=YY_START;
724 <SComment>\n { /* end of special comment */
725 copyToOutput(yyscanner," */",3);
726 copyToOutput(yyscanner,yytext,(int)yyleng);
727 yyextra->inSpecialComment=FALSE;
728 yyextra->inRoseComment=FALSE;
732 copyToOutput(yyscanner,"/‍**",8);
735 copyToOutput(yyscanner,"*‍/",7);
738 copyToOutput(yyscanner,yytext,(int)yyleng);
740 <ReadLine>[^\\@\n\*/]* {
741 copyToOutput(yyscanner,yytext,(int)yyleng);
743 <ReadLine>[^\\@\n\*/]*/\n {
744 copyToOutput(yyscanner,yytext,(int)yyleng);
745 BEGIN(yyextra->readLineCtx);
747 <CComment,ReadLine>[\\@][\\@][~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
748 copyToOutput(yyscanner,yytext,(int)yyleng);
750 <CComment,ReadLine>[\\@]"cond"/[^a-z_A-Z0-9] { // conditional section
751 yyextra->condCtx = YY_START;
754 <CComment,ReadLine>[\\@]"endcond"/[^a-z_A-Z0-9] { // end of conditional section
755 bool oldSkip=yyextra->skip;
756 endCondSection(yyscanner);
757 if (YY_START==CComment && oldSkip && !yyextra->skip)
759 //printf("** Adding start of comment!\n");
760 if (yyextra->lang!=SrcLangExt_Python &&
761 yyextra->lang!=SrcLangExt_VHDL &&
762 yyextra->lang!=SrcLangExt_Markdown &&
763 yyextra->lang!=SrcLangExt_Fortran)
767 if (yyextra->specialComment)
774 <CondLine>[!()&| \ta-z_A-Z0-9.\-]+ {
775 handleCondSectionId(yyscanner,yytext);
777 <CComment,ReadLine>[\\@]"cond"[ \t\r]*/\n {
778 yyextra->condCtx=YY_START;
779 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
781 <CondLine>. { // forgot section id?
782 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
783 if (*yytext=='\n') yyextra->lineNr++;
785 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias without arguments
786 replaceAliases(yyscanner,yytext);
788 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]*"{" { // expand alias with arguments
789 yyextra->lastBlockContext=YY_START;
790 yyextra->blockCount=1;
791 yyextra->aliasString=yytext;
792 yyextra->lastEscaped=0;
793 BEGIN( ReadAliasArgs );
795 <ReadAliasArgs>^[ \t]*"//"[/!]/[^\n]+ { // skip leading special comments (see bug 618079)
797 <ReadAliasArgs>"*/" { // oops, end of comment in the middle of an alias?
798 if (yyextra->lang==SrcLangExt_Python)
802 else // abort the alias, restart scanning
804 copyToOutput(yyscanner,yyextra->aliasString,yyextra->aliasString.length());
805 copyToOutput(yyscanner,yytext,(int)yyleng);
809 <ReadAliasArgs>[^{}\n\\\*]+ {
810 yyextra->aliasString+=yytext;
811 yyextra->lastEscaped=FALSE;
813 <ReadAliasArgs>"\\" {
814 if (yyextra->lastEscaped) yyextra->lastEscaped=FALSE;
815 else yyextra->lastEscaped=TRUE;
816 yyextra->aliasString+=yytext;
819 yyextra->aliasString+=yytext;
821 yyextra->lastEscaped=FALSE;
824 yyextra->aliasString+=yytext;
825 if (!yyextra->lastEscaped) yyextra->blockCount++;
826 yyextra->lastEscaped=FALSE;
829 yyextra->aliasString+=yytext;
830 if (!yyextra->lastEscaped) yyextra->blockCount--;
831 if (yyextra->blockCount==0)
833 replaceAliases(yyscanner,yyextra->aliasString);
834 BEGIN( yyextra->lastBlockContext );
836 yyextra->lastEscaped=FALSE;
839 yyextra->aliasString+=yytext;
840 yyextra->lastEscaped=FALSE;
843 copyToOutput(yyscanner,yytext,(int)yyleng);
848 static void replaceCommentMarker(yyscan_t yyscanner,const char *s,int len)
850 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
853 // copy leading blanks
854 while ((c=*p) && (c==' ' || c=='\t' || c=='\n'))
857 yyextra->lineNr += c=='\n';
860 // replace start of comment marker by blanks and the last character by a *
862 while ((c=*p) && (c=='/' || c=='!' || c=='#'))
866 if (*p=='<') // comment-after-item marker
871 if (c=='!') // end after first !
883 if (blanks>1) ADDCHAR('*');
886 // copy comment line to output
887 ADDARRAY(p,len-(int)(p-s));
890 static inline int computeIndent(const char *s)
893 static int tabSize=Config_getInt(TAB_SIZE);
899 else if (c=='\t') col+=tabSize-(col%tabSize);
905 static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len)
907 int tabSize=Config_getInt(TAB_SIZE);
908 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
910 if (yyextra->skip) // only add newlines.
922 yyextra->col+=tabSize-(yyextra->col%tabSize);
937 case '\n': yyextra->col=0;
938 //fprintf(stderr,"---> copy %d\n",g_lineNr);
939 yyextra->lineNr++; break;
940 case '\t': yyextra->col+=tabSize-(yyextra->col%tabSize); break;
941 default: yyextra->col++; break;
947 static void startCondSection(yyscan_t yyscanner,const char *sectId)
949 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
950 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
952 bool expResult = prs.parse(yyextra->fileName,yyextra->lineNr,sectId);
953 yyextra->condStack.push(new CondCtx(yyextra->lineNr,sectId,yyextra->skip));
954 if (!expResult) // not enabled
960 static void endCondSection(yyscan_t yyscanner)
962 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
963 if (yyextra->condStack.isEmpty())
965 warn(yyextra->fileName,yyextra->lineNr,"Found \\endcond command without matching \\cond");
970 CondCtx *ctx = yyextra->condStack.pop();
971 yyextra->skip=ctx->skip;
973 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
976 static void handleCondSectionId(yyscan_t yyscanner,const char *expression)
978 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
979 bool oldSkip=yyextra->skip;
980 startCondSection(yyscanner,expression);
981 if ((yyextra->condCtx==CComment || yyextra->readLineCtx==SComment) &&
982 !oldSkip && yyextra->skip)
984 if (yyextra->lang!=SrcLangExt_Python &&
985 yyextra->lang!=SrcLangExt_VHDL &&
986 yyextra->lang!=SrcLangExt_Markdown &&
987 yyextra->lang!=SrcLangExt_Fortran)
993 if (yyextra->readLineCtx==SComment)
999 BEGIN(yyextra->condCtx);
1003 /** copies string \a s with length \a len to the output, while
1004 * replacing any alias commands found in the string.
1006 static void replaceAliases(yyscan_t yyscanner,const char *s)
1008 QCString result = resolveAliasCmd(s);
1009 //printf("replaceAliases(%s)->'%s'\n",s,result.data());
1010 copyToOutput(yyscanner,result,result.length());
1014 static int yyread(yyscan_t yyscanner,char *buf,int max_size)
1016 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1017 int bytesInBuf = yyextra->inBuf->curPos()-yyextra->inBufPos;
1018 int bytesToCopy = QMIN(max_size,bytesInBuf);
1019 memcpy(buf,yyextra->inBuf->data()+yyextra->inBufPos,bytesToCopy);
1020 yyextra->inBufPos+=bytesToCopy;
1024 static void replaceComment(yyscan_t yyscanner,int offset)
1026 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1027 if (yyextra->mlBrief || yyextra->skip)
1029 copyToOutput(yyscanner,yytext,(int)yyleng);
1033 //printf("replaceComment(%s)\n",yytext);
1034 int i=computeIndent(&yytext[offset]);
1035 if (i==yyextra->blockHeadCol)
1037 replaceCommentMarker(yyscanner,yytext,(int)yyleng);
1041 copyToOutput(yyscanner," */",3);
1042 int i;for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
1043 yyextra->inSpecialComment=FALSE;
1049 // simplified way to know if this is fixed form
1050 // duplicate in fortrancode.l
1051 static bool recognizeFixedForm(const char* contents)
1054 bool skipLine=FALSE;
1059 switch(contents[i]) {
1071 if(column==1) return TRUE;
1075 if(column>1 && column<7) return FALSE;
1080 if(column==7) return TRUE;
1088 /*! This function does three things:
1089 * -# It converts multi-line C++ style comment blocks (that are aligned)
1090 * to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
1091 * -# It replaces aliases with their definition (see ALIASES)
1092 * -# It handles conditional sections (cond...endcond blocks)
1094 void convertCppComments(BufStr *inBuf,BufStr *outBuf,const char *fileName)
1097 commentcnvYY_state extra;
1098 commentcnvYYlex_init_extra(&extra,&yyscanner);
1100 commentcnvYYset_debug(1,yyscanner);
1102 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1103 //printf("convertCppComments(%s)\n",fileName);
1104 yyextra->inBuf = inBuf;
1105 yyextra->outBuf = outBuf;
1106 yyextra->inBufPos = 0;
1108 yyextra->mlBrief = Config_getBool(MULTILINE_CPP_IS_BRIEF);
1109 yyextra->skip = FALSE;
1110 yyextra->fileName = fileName;
1111 yyextra->lang = getLanguageFromFileName(fileName);
1112 yyextra->pythonDocString = FALSE;
1113 yyextra->lineNr = 1;
1114 yyextra->condStack.clear();
1115 yyextra->condStack.setAutoDelete(TRUE);
1116 yyextra->commentStack.clear();
1117 yyextra->commentStack.setAutoDelete(TRUE);
1118 yyextra->vhdl = FALSE;
1120 printlex(yy_flex_debug, TRUE, __FILE__, fileName);
1121 yyextra->isFixedForm = FALSE;
1122 if (yyextra->lang==SrcLangExt_Fortran)
1124 yyextra->isFixedForm = recognizeFixedForm(inBuf->data());
1127 if (yyextra->lang==SrcLangExt_Markdown)
1129 yyextra->nestingCount=0;
1131 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
1138 while (!yyextra->condStack.isEmpty())
1140 CondCtx *ctx = yyextra->condStack.pop();
1141 QCString sectionInfo = " ";
1142 if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",ctx->sectionId.stripWhiteSpace().data());
1143 warn(yyextra->fileName,ctx->lineNr,"Conditional section%sdoes not have "
1144 "a corresponding \\endcond command within this file.",sectionInfo.data());
1146 if (yyextra->nestingCount>0 && yyextra->lang!=SrcLangExt_Markdown)
1148 QCString tmp= "(probable line reference: ";
1150 while (!yyextra->commentStack.isEmpty())
1152 CommentCtx *ctx = yyextra->commentStack.pop();
1153 if (!first) tmp += ", ";
1154 tmp += QCString().setNum(ctx->lineNr);
1159 warn(yyextra->fileName,yyextra->lineNr,"Reached end of file while still inside a (nested) comment. "
1160 "Nesting level %d %s",yyextra->nestingCount,tmp.data());
1162 yyextra->commentStack.clear();
1163 yyextra->nestingCount = 0;
1164 if (Debug::isFlagSet(Debug::CommentCnv))
1166 yyextra->outBuf->at(yyextra->outBuf->curPos())='\0';
1167 Debug::print(Debug::CommentCnv,0,"-----------\nCommentCnv: %s\n"
1168 "output=[\n%s]\n-----------\n",fileName,yyextra->outBuf->data()
1171 printlex(yy_flex_debug, FALSE, __FILE__, fileName);
1172 commentcnvYYlex_destroy(yyscanner);
1176 //----------------------------------------------------------------------------
1178 #include "commentcnv.l.h"