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 *"
33 #include <qtextstream.h>
42 #include "condparser.h"
47 #define YY_NO_UNISTD_H 1
49 #define ADDCHAR(c) yyextra->outBuf->addChar(c)
50 #define ADDARRAY(a,s) yyextra->outBuf->addArray(a,s)
52 #define USE_STATE2STRING 0
56 CondCtx(int line,QCString id,bool b)
57 : lineNr(line),sectionId(id), skip(b) {}
70 struct commentcnvYY_state
83 QStack<CondCtx> condStack;
84 QStack<CommentCtx> commentStack;
86 int lastCommentContext = 0;
87 bool inSpecialComment = FALSE;
88 bool inRoseComment= FALSE;
89 int stringContext = 0;
92 bool specialComment = FALSE;
96 bool lastEscaped = FALSE;
97 int lastBlockContext= 0;
98 bool pythonDocString = FALSE;
101 bool vhdl = FALSE; // for VHDL old style --! comment
103 SrcLangExt lang = SrcLangExt_Unknown;
104 bool isFixedForm = FALSE; // For Fortran
108 static const char *stateToString(int state);
110 static inline int computeIndent(const char *s);
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);
125 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
130 MAILADR ("mailto:")?[a-z_A-Z0-9.+-]+"@"[a-z_A-Z0-9-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
147 <Scan>[^"'!\/\n\\#,\-]* { /* eat anything that is not " / , or \n */
148 copyToOutput(yyscanner,yytext,(int)yyleng);
150 <Scan>[,] { /* eat , so we have a nice separator in long initialization lines */
151 copyToOutput(yyscanner,yytext,(int)yyleng);
153 <Scan>"\"\"\""! { /* start of python long comment */
154 if (yyextra->lang!=SrcLangExt_Python)
160 yyextra->pythonDocString = TRUE;
161 yyextra->nestingCount=1;
162 yyextra->commentStack.clear(); /* to be on the save side */
163 copyToOutput(yyscanner,yytext,(int)yyleng);
165 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
169 if (yyextra->lang!=SrcLangExt_Fortran)
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 */
179 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
182 <Scan>[Cc\*][><!]/.*\n {
183 if (yyextra->lang!=SrcLangExt_Fortran)
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))
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 */
196 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
205 if (yyextra->lang!=SrcLangExt_Fortran)
211 copyToOutput(yyscanner,yytext,(int)yyleng);
215 if (yyextra->lang!=SrcLangExt_Fortran)
221 if (yyextra->col == 0)
223 copyToOutput(yyscanner,yytext,(int)yyleng);
231 <Scan>"\"" { /* start of a string */
232 copyToOutput(yyscanner,yytext,(int)yyleng);
233 yyextra->stringContext = YY_START;
237 copyToOutput(yyscanner,yytext,(int)yyleng);
238 yyextra->charContext = YY_START;
239 if (yyextra->lang!=SrcLangExt_VHDL)
244 <Scan>\n { /* new line */
245 copyToOutput(yyscanner,yytext,(int)yyleng);
247 <Scan>"//!"/.*\n[ \t]*"//"[\/!][^\/] | /* start C++ style special comment block */
248 <Scan>("///"[/]*)/[^/].*\n[ \t]*"//"[\/!][^\/] { /* start C++ style special comment block */
249 if (yyextra->mlBrief)
251 REJECT; // bail out if we do not need to convert
258 while (i<(int)yyleng && yytext[i]=='/') i++;
260 yyextra->blockHeadCol=yyextra->col;
261 copyToOutput(yyscanner,"/**",3);
262 replaceAliases(yyscanner,yytext+i);
263 yyextra->inSpecialComment=TRUE;
265 yyextra->readLineCtx=SComment;
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;
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;
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;
290 <Scan>"/**/" { /* avoid matching next rule for empty C comment, see bug 711723 */
291 copyToOutput(yyscanner,yytext,(int)yyleng);
293 <Scan>"/*"[*!]? { /* start of a C comment */
294 if (yyextra->lang==SrcLangExt_Python)
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);
303 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
306 if (yyextra->lang!=SrcLangExt_Python)
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 */
316 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
320 if (yyextra->lang!=SrcLangExt_VHDL)
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 */
331 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
335 if (yyextra->lang!=SrcLangExt_Fortran)
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 */
345 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
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);
352 <CComment>"{@code"/[ \t\n] {
353 copyToOutput(yyscanner,"@code",5);
354 yyextra->lastCommentContext = YY_START;
355 yyextra->javaBlock=1;
356 yyextra->blockName=&yytext[1];
359 <CComment,ReadLine>^[ \t]*("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
360 if (!Config_getBool(MARKDOWN_SUPPORT))
364 copyToOutput(yyscanner,yytext,(int)yyleng);
365 yyextra->lastCommentContext = YY_START;
366 yyextra->javaBlock=0;
367 yyextra->blockName=QCString(yytext).stripWhiteSpace().left(3);
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)
376 yyextra->blockName="uml";
380 yyextra->blockName=&yytext[1];
384 <CComment,ReadLine>[\\@]("f$"|"f["|"f{") {
385 copyToOutput(yyscanner,yytext,(int)yyleng);
386 yyextra->blockName=&yytext[1];
387 if (yyextra->blockName.at(1)=='[')
389 yyextra->blockName.at(1)=']';
391 else if (yyextra->blockName.at(1)=='{')
393 yyextra->blockName.at(1)='}';
395 yyextra->lastCommentContext = YY_START;
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;
404 <Scan>. { /* any other character */
405 copyToOutput(yyscanner,yytext,(int)yyleng);
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
411 BEGIN(yyextra->lastCommentContext);
413 else if (&yytext[4]==yyextra->blockName)
415 BEGIN(yyextra->lastCommentContext);
419 if (yyextra->javaBlock==0)
425 yyextra->javaBlock++;
426 copyToOutput(yyscanner,yytext,(int)yyleng);
430 if (yyextra->javaBlock==0)
436 yyextra->javaBlock--;
437 if (yyextra->javaBlock==0)
439 copyToOutput(yyscanner," @endcode ",10);
440 BEGIN(yyextra->lastCommentContext);
444 copyToOutput(yyscanner,yytext,(int)yyleng);
448 <VerbatimCode>("```"[`]*|"~~~"[~]*) { /* end of markdown code block */
449 copyToOutput(yyscanner,yytext,(int)yyleng);
450 if (yytext[0]==yyextra->blockName[0])
452 BEGIN(yyextra->lastCommentContext);
455 <VerbatimCode>[\\@]("enddot"|"endcode"|"endmsc"|"enduml") { /* end of verbatim block */
456 copyToOutput(yyscanner,yytext,(int)yyleng);
457 if (&yytext[4]==yyextra->blockName)
459 BEGIN(yyextra->lastCommentContext);
462 <VerbatimCode>^[ \t]*"//"[\!\/]? { /* skip leading comments */
463 if (!yyextra->inSpecialComment)
465 copyToOutput(yyscanner,yytext,(int)yyleng);
470 while (yytext[l]==' ' || yytext[l]=='\t')
474 copyToOutput(yyscanner,yytext,l);
475 if (yyleng-l==3) // ends with //! or ///
477 copyToOutput(yyscanner," * ",3);
481 copyToOutput(yyscanner,"//",2);
485 <Verbatim,VerbatimCode>[^`~@\/\\\n{}]* { /* any character not a backslash or new line or } */
486 copyToOutput(yyscanner,yytext,(int)yyleng);
488 <Verbatim,VerbatimCode>\n { /* new line in verbatim block */
489 copyToOutput(yyscanner,yytext,(int)yyleng);
491 <Verbatim>^[ \t]*"///" {
492 if (yyextra->blockName=="dot" || yyextra->blockName=="msc" || yyextra->blockName=="uml" || yyextra->blockName.at(0)=='f')
494 // see bug 487871, strip /// from dot images and formulas.
496 while (yytext[l]==' ' || yytext[l]=='\t')
500 copyToOutput(yyscanner,yytext,l);
501 copyToOutput(yyscanner," ",3);
503 else // even slashes are verbatim (e.g. \verbatim, \code)
508 <Verbatim,VerbatimCode>. { /* any other character */
509 copyToOutput(yyscanner,yytext,(int)yyleng);
511 <SkipString>\\. { /* escaped character in string */
512 if (yyextra->lang==SrcLangExt_Fortran)
515 copyToOutput(yyscanner,yytext,1);
519 copyToOutput(yyscanner,yytext,(int)yyleng);
522 <SkipString>"\"" { /* end of string */
523 copyToOutput(yyscanner,yytext,(int)yyleng);
524 BEGIN(yyextra->stringContext);
526 <SkipString>. { /* any other string character */
527 copyToOutput(yyscanner,yytext,(int)yyleng);
529 <SkipString>\n { /* new line inside string (illegal for some compilers) */
530 copyToOutput(yyscanner,yytext,(int)yyleng);
532 <SkipChar>\\. { /* escaped character */
533 if (yyextra->lang==SrcLangExt_Fortran)
536 copyToOutput(yyscanner,yytext,1);
540 copyToOutput(yyscanner,yytext,(int)yyleng);
543 <SkipChar>' { /* end of character literal */
544 copyToOutput(yyscanner,yytext,(int)yyleng);
545 BEGIN(yyextra->charContext);
547 <SkipChar>. { /* any other string character */
548 copyToOutput(yyscanner,yytext,(int)yyleng);
550 <SkipChar>\n { /* new line character */
551 copyToOutput(yyscanner,yytext,(int)yyleng);
554 <CComment>[^ `~<\\!@*\n{\"\/]* { /* anything that is not a '*' or command */
555 copyToOutput(yyscanner,yytext,(int)yyleng);
557 <CComment>"*"+[^*/\\@\n{\"]* { /* stars without slashes */
558 copyToOutput(yyscanner,yytext,(int)yyleng);
560 <CComment>"\"\"\"" { /* end of Python docstring */
561 if (yyextra->lang!=SrcLangExt_Python)
567 yyextra->nestingCount--;
568 yyextra->pythonDocString = FALSE;
569 copyToOutput(yyscanner,yytext,(int)yyleng);
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)
581 <CComment>"/"+"*" { /* nested C comment */
582 if (yyextra->lang==SrcLangExt_Python ||
583 yyextra->lang==SrcLangExt_Markdown)
587 yyextra->nestingCount++;
588 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
589 copyToOutput(yyscanner,yytext,(int)yyleng);
591 <CComment>"*"+"/" { /* end of C comment */
592 if (yyextra->lang==SrcLangExt_Python ||
593 yyextra->lang==SrcLangExt_Markdown)
599 copyToOutput(yyscanner,yytext,(int)yyleng);
600 yyextra->nestingCount--;
601 if (yyextra->nestingCount<=0)
607 //yyextra->nestingCount--;
608 delete yyextra->commentStack.pop();
612 /* Python an VHDL share CComment, so special attention for ending comments is required */
613 <CComment>"\n"/[ \t]*"#" {
614 if (yyextra->lang!=SrcLangExt_VHDL)
620 if (yyextra->vhdl) // inside --! comment
622 yyextra->vhdl = FALSE;
623 copyToOutput(yyscanner,yytext,(int)yyleng);
626 else // C-type comment
632 <CComment>"\n"/[ \t]*"-" {
633 if (yyextra->lang!=SrcLangExt_Python || yyextra->pythonDocString)
639 copyToOutput(yyscanner,yytext,(int)yyleng);
643 <CComment>"\n"/[ \t]*[^ \t#\-] {
644 if (yyextra->lang==SrcLangExt_Python)
646 if (yyextra->pythonDocString)
652 copyToOutput(yyscanner,yytext,(int)yyleng);
656 else if (yyextra->lang==SrcLangExt_VHDL)
658 if (yyextra->vhdl) // inside --! comment
660 yyextra->vhdl = FALSE;
661 copyToOutput(yyscanner,yytext,(int)yyleng);
664 else // C-type comment
674 /* removed for bug 674842 (bug was introduced in rev 768)
676 yyextra->charContext = YY_START;
677 copyToOutput(yyscanner,yytext,(int)yyleng);
681 yyextra->stringContext = YY_START;
682 copyToOutput(yyscanner,yytext,(int)yyleng);
687 copyToOutput(yyscanner,yytext,(int)yyleng);
689 <SComment>^[ \t]*"///"[\/]*/\n {
690 replaceComment(yyscanner,0);
692 <SComment>\n[ \t]*"///"[\/]*/\n {
693 replaceComment(yyscanner,1);
695 <SComment>^[ \t]*"///"[^\/\n]/.*\n {
696 replaceComment(yyscanner,0);
697 yyextra->readLineCtx=YY_START;
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;
708 <SComment>\n[ \t]*"///"[^\/\n]/.*\n {
709 replaceComment(yyscanner,1);
710 yyextra->readLineCtx=YY_START;
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;
720 <SComment>\n[ \t]*"//!" |
721 <SComment>\n[ \t]*"//!<"/.*\n |
722 <SComment>\n[ \t]*"//!"[^<\n]/.*\n {
723 replaceComment(yyscanner,1);
724 yyextra->readLineCtx=YY_START;
727 <SComment>^[ \t]*"//##"/.*\n {
728 if (!yyextra->inRoseComment)
734 replaceComment(yyscanner,0);
735 yyextra->readLineCtx=YY_START;
739 <SComment>\n[ \t]*"//##"/.*\n {
740 if (!yyextra->inRoseComment)
746 replaceComment(yyscanner,1);
747 yyextra->readLineCtx=YY_START;
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;
759 copyToOutput(yyscanner,"/‍**",8);
762 copyToOutput(yyscanner,"*‍/",7);
765 copyToOutput(yyscanner,yytext,(int)yyleng);
767 <ReadLine>[^\\@\n\*/]* {
768 copyToOutput(yyscanner,yytext,(int)yyleng);
770 <ReadLine>[^\\@\n\*/]*/\n {
771 copyToOutput(yyscanner,yytext,(int)yyleng);
772 BEGIN(yyextra->readLineCtx);
774 <CComment,ReadLine>[\\@][\\@][~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
775 copyToOutput(yyscanner,yytext,(int)yyleng);
777 <CComment,ReadLine>[\\@]"cond"/[^a-z_A-Z0-9] { // conditional section
778 yyextra->condCtx = YY_START;
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)
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)
794 if (yyextra->specialComment)
801 <CondLine>[!()&| \ta-z_A-Z0-9.\-]+ {
802 handleCondSectionId(yyscanner,yytext);
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
808 <CondLine>. { // forgot section id?
809 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
810 if (*yytext=='\n') yyextra->lineNr++;
812 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias without arguments
813 replaceAliases(yyscanner,yytext);
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 );
822 <ReadAliasArgs>^[ \t]*"//"[/!]/[^\n]+ { // skip leading special comments (see bug 618079)
824 <ReadAliasArgs>"*/" { // oops, end of comment in the middle of an alias?
825 if (yyextra->lang==SrcLangExt_Python)
829 else // abort the alias, restart scanning
831 copyToOutput(yyscanner,yyextra->aliasString,yyextra->aliasString.length());
832 copyToOutput(yyscanner,yytext,(int)yyleng);
836 <ReadAliasArgs>[^{}\n\\\*]+ {
837 yyextra->aliasString+=yytext;
838 yyextra->lastEscaped=FALSE;
840 <ReadAliasArgs>"\\" {
841 if (yyextra->lastEscaped) yyextra->lastEscaped=FALSE;
842 else yyextra->lastEscaped=TRUE;
843 yyextra->aliasString+=yytext;
846 yyextra->aliasString+=yytext;
848 yyextra->lastEscaped=FALSE;
851 yyextra->aliasString+=yytext;
852 if (!yyextra->lastEscaped) yyextra->blockCount++;
853 yyextra->lastEscaped=FALSE;
856 yyextra->aliasString+=yytext;
857 if (!yyextra->lastEscaped) yyextra->blockCount--;
858 if (yyextra->blockCount==0)
860 replaceAliases(yyscanner,yyextra->aliasString);
861 BEGIN( yyextra->lastBlockContext );
863 yyextra->lastEscaped=FALSE;
866 yyextra->aliasString+=yytext;
867 yyextra->lastEscaped=FALSE;
870 copyToOutput(yyscanner,yytext,(int)yyleng);
875 static void replaceCommentMarker(yyscan_t yyscanner,const char *s,int len)
877 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
880 // copy leading blanks
881 while ((c=*p) && (c==' ' || c=='\t' || c=='\n'))
884 yyextra->lineNr += c=='\n';
887 // replace start of comment marker by blanks and the last character by a *
889 while ((c=*p) && (c=='/' || c=='!' || c=='#'))
893 if (*p=='<') // comment-after-item marker
898 if (c=='!') // end after first !
910 if (blanks>1) ADDCHAR('*');
913 // copy comment line to output
914 ADDARRAY(p,len-(int)(p-s));
917 static inline int computeIndent(const char *s)
920 static int tabSize=Config_getInt(TAB_SIZE);
926 else if (c=='\t') col+=tabSize-(col%tabSize);
932 static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len)
934 int tabSize=Config_getInt(TAB_SIZE);
935 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
937 if (yyextra->skip) // only add newlines.
949 yyextra->col+=tabSize-(yyextra->col%tabSize);
964 case '\n': yyextra->col=0;
965 //fprintf(stderr,"---> copy %d\n",g_lineNr);
966 yyextra->lineNr++; break;
967 case '\t': yyextra->col+=tabSize-(yyextra->col%tabSize); break;
968 default: yyextra->col++; break;
974 static void startCondSection(yyscan_t yyscanner,const char *sectId)
976 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
977 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
979 bool expResult = prs.parse(yyextra->fileName,yyextra->lineNr,sectId);
980 yyextra->condStack.push(new CondCtx(yyextra->lineNr,sectId,yyextra->skip));
981 if (!expResult) // not enabled
987 static void endCondSection(yyscan_t yyscanner)
989 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
990 if (yyextra->condStack.isEmpty())
992 warn(yyextra->fileName,yyextra->lineNr,"Found \\endcond command without matching \\cond");
997 CondCtx *ctx = yyextra->condStack.pop();
998 yyextra->skip=ctx->skip;
1000 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1003 static void handleCondSectionId(yyscan_t yyscanner,const char *expression)
1005 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1006 bool oldSkip=yyextra->skip;
1007 startCondSection(yyscanner,expression);
1008 if ((yyextra->condCtx==CComment || yyextra->readLineCtx==SComment) &&
1009 !oldSkip && yyextra->skip)
1011 if (yyextra->lang!=SrcLangExt_Python &&
1012 yyextra->lang!=SrcLangExt_VHDL &&
1013 yyextra->lang!=SrcLangExt_Markdown &&
1014 yyextra->lang!=SrcLangExt_Fortran)
1020 if (yyextra->readLineCtx==SComment)
1026 BEGIN(yyextra->condCtx);
1030 /** copies string \a s with length \a len to the output, while
1031 * replacing any alias commands found in the string.
1033 static void replaceAliases(yyscan_t yyscanner,const char *s)
1035 QCString result = resolveAliasCmd(s);
1036 //printf("replaceAliases(%s)->'%s'\n",s,result.data());
1037 copyToOutput(yyscanner,result,result.length());
1041 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
1043 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1044 yy_size_t bytesInBuf = yyextra->inBuf->curPos()-yyextra->inBufPos;
1045 yy_size_t bytesToCopy = QMIN(max_size,bytesInBuf);
1046 memcpy(buf,yyextra->inBuf->data()+yyextra->inBufPos,bytesToCopy);
1047 yyextra->inBufPos+=bytesToCopy;
1051 static void replaceComment(yyscan_t yyscanner,int offset)
1053 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1054 if (yyextra->mlBrief || yyextra->skip)
1056 copyToOutput(yyscanner,yytext,(int)yyleng);
1060 //printf("replaceComment(%s)\n",yytext);
1061 int i=computeIndent(&yytext[offset]);
1062 if (i==yyextra->blockHeadCol)
1064 replaceCommentMarker(yyscanner,yytext,(int)yyleng);
1068 copyToOutput(yyscanner," */",3);
1069 for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
1070 yyextra->inSpecialComment=FALSE;
1076 // simplified way to know if this is fixed form
1077 // duplicate in fortrancode.l
1078 static bool recognizeFixedForm(const char* contents)
1081 bool skipLine=FALSE;
1086 switch(contents[i]) {
1098 if(column==1) return TRUE;
1102 if(column>1 && column<7) return FALSE;
1107 if(column==7) return TRUE;
1115 /*! This function does three things:
1116 * -# It converts multi-line C++ style comment blocks (that are aligned)
1117 * to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
1118 * -# It replaces aliases with their definition (see ALIASES)
1119 * -# It handles conditional sections (cond...endcond blocks)
1121 void convertCppComments(BufStr *inBuf,BufStr *outBuf,const char *fileName)
1124 commentcnvYY_state extra;
1125 commentcnvYYlex_init_extra(&extra,&yyscanner);
1127 commentcnvYYset_debug(1,yyscanner);
1129 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1130 //printf("convertCppComments(%s)\n",fileName);
1131 yyextra->inBuf = inBuf;
1132 yyextra->outBuf = outBuf;
1133 yyextra->inBufPos = 0;
1135 yyextra->mlBrief = Config_getBool(MULTILINE_CPP_IS_BRIEF);
1136 yyextra->skip = FALSE;
1137 yyextra->fileName = fileName;
1138 yyextra->lang = getLanguageFromFileName(fileName);
1139 yyextra->pythonDocString = FALSE;
1140 yyextra->lineNr = 1;
1141 yyextra->condStack.clear();
1142 yyextra->condStack.setAutoDelete(TRUE);
1143 yyextra->commentStack.clear();
1144 yyextra->commentStack.setAutoDelete(TRUE);
1145 yyextra->vhdl = FALSE;
1147 printlex(yy_flex_debug, TRUE, __FILE__, fileName);
1148 yyextra->isFixedForm = FALSE;
1149 if (yyextra->lang==SrcLangExt_Fortran)
1151 yyextra->isFixedForm = recognizeFixedForm(inBuf->data());
1154 if (yyextra->lang==SrcLangExt_Markdown)
1156 yyextra->nestingCount=0;
1158 yyextra->commentStack.push(new CommentCtx(yyextra->lineNr));
1165 while (!yyextra->condStack.isEmpty())
1167 CondCtx *ctx = yyextra->condStack.pop();
1168 QCString sectionInfo = " ";
1169 if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",ctx->sectionId.stripWhiteSpace().data());
1170 warn(yyextra->fileName,ctx->lineNr,"Conditional section%sdoes not have "
1171 "a corresponding \\endcond command within this file.",sectionInfo.data());
1173 if (yyextra->nestingCount>0 && yyextra->lang!=SrcLangExt_Markdown)
1175 QCString tmp= "(probable line reference: ";
1177 while (!yyextra->commentStack.isEmpty())
1179 CommentCtx *ctx = yyextra->commentStack.pop();
1180 if (!first) tmp += ", ";
1181 tmp += QCString().setNum(ctx->lineNr);
1186 warn(yyextra->fileName,yyextra->lineNr,"Reached end of file while still inside a (nested) comment. "
1187 "Nesting level %d %s",yyextra->nestingCount,tmp.data());
1189 yyextra->commentStack.clear();
1190 yyextra->nestingCount = 0;
1191 if (Debug::isFlagSet(Debug::CommentCnv))
1193 yyextra->outBuf->at(yyextra->outBuf->curPos())='\0';
1194 Debug::print(Debug::CommentCnv,0,"-----------\nCommentCnv: %s\n"
1195 "output=[\n%s]\n-----------\n",fileName,yyextra->outBuf->data()
1198 printlex(yy_flex_debug, FALSE, __FILE__, fileName);
1199 commentcnvYYlex_destroy(yyscanner);
1203 //----------------------------------------------------------------------------
1205 #if USE_STATE2STRING
1206 #include "commentcnv.l.h"