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 *"
23 // forward declare yyscan_t to improve type safety
24 #define YY_TYPEDEF_YY_SCANNER_T
26 typedef yyguts_t *yyscan_t;
43 #include "condparser.h"
48 #define YY_NO_UNISTD_H 1
50 #define ADDCHAR(c) yyextra->outBuf->addChar(c)
51 #define ADDARRAY(a,s) yyextra->outBuf->addArray(a,s)
53 #define USE_STATE2STRING 0
55 struct commentcnvYY_CondCtx
57 commentcnvYY_CondCtx(int line,QCString id,bool b)
58 : lineNr(line),sectionId(id), skip(b) {}
71 struct commentcnvYY_state
75 yy_size_t inBufPos = 0;
84 std::stack<commentcnvYY_CondCtx> condStack;
85 std::stack<int> commentStack;
87 int lastCommentContext = 0;
88 bool inSpecialComment = FALSE;
89 bool inRoseComment= FALSE;
90 int stringContext = 0;
93 bool specialComment = FALSE;
97 bool lastEscaped = FALSE;
98 int lastBlockContext= 0;
99 bool pythonDocString = FALSE;
102 bool vhdl = FALSE; // for VHDL old style --! comment
104 SrcLangExt lang = SrcLangExt_Unknown;
105 bool isFixedForm = FALSE; // For Fortran
109 static const char *stateToString(int state);
111 static inline int computeIndent(const char *s);
113 static void replaceCommentMarker(yyscan_t yyscanner,const char *s,int len);
114 static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len);
115 static void startCondSection(yyscan_t yyscanner,const QCString §Id);
116 static void endCondSection(yyscan_t yyscanner);
117 static void handleCondSectionId(yyscan_t yyscanner,const char *expression);
118 static void replaceAliases(yyscan_t yyscanner,const QCString &s);
119 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
120 static void replaceComment(yyscan_t yyscanner,int offset);
121 static void clearCommentStack(yyscan_t yyscanner);
127 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
132 MAILADR ("mailto:")?[a-z_A-Z0-9.+-]+"@"[a-z_A-Z0-9-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
148 //- start: NUMBER -------------------------------------------------------------------------
149 // Note same defines in code.l: keep in sync
150 DECIMAL_INTEGER [1-9][0-9']*[0-9]?[uU]?[lL]?[lL]?
151 HEXADECIMAL_INTEGER "0"[xX][0-9a-zA-Z']+[0-9a-zA-Z]?
152 OCTAL_INTEGER "0"[0-7][0-7']+[0-7]?
153 BINARY_INTEGER "0"[bB][01][01']*[01]?
154 INTEGER_NUMBER {DECIMAL_INTEGER}|{HEXADECIMAL_INTEGER}|{OCTAL_INTEGER}|{BINARY_INTEGER}
158 DIGIT_SEQ [0-9][0-9']*[0-9]?
159 FRAC_CONST {DIGIT_SEQ}"."|{DIGIT_SEQ}?"."{DIGIT_SEQ}
160 FP_EXP [eE][+-]?{DIGIT_SEQ}
161 DEC_FP1 {FRAC_CONST}{FP_EXP}?{FP_SUF}?
162 DEC_FP2 {DIGIT_SEQ}{FP_EXP}{FP_SUF}
164 HEX_DIGIT_SEQ [0-9a-fA-F][0-9a-fA-F']*[0-9a-fA-F]?
165 HEX_FRAC_CONST {HEX_DIGIT_SEQ}"."|{HEX_DIGIT_SEQ}?"."{HEX_DIGIT_SEQ}
166 BIN_EXP [pP][+-]?{DIGIT_SEQ}
167 HEX_FP1 "0"[xX]{HEX_FRAC_CONST}{BIN_EXP}{FP_SUF}?
168 HEX_FP2 "0"[xX]{HEX_DIGIT_SEQ}{BIN_EXP}{FP_SUF}?
170 FLOAT_DECIMAL {DEC_FP1}|{DEC_FP2}
171 FLOAT_HEXADECIMAL {HEX_FP1}|{HEX_FP2}
172 FLOAT_NUMBER {FLOAT_DECIMAL}|{FLOAT_HEXADECIMAL}
173 NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
174 //- end: NUMBER ---------------------------------------------------------------------------
183 // Optional any character
186 // Optional white space
188 // readline non special
195 <Scan>{NUMBER} { //Note similar code in code.l
196 if (yyextra->lang!=SrcLangExt_Cpp) REJECT;
197 copyToOutput(yyscanner,yytext,(int)yyleng);
199 <Scan>[^"'!\/\n\\#,\-=; \t]* { /* eat anything that is not " / , or \n */
200 copyToOutput(yyscanner,yytext,(int)yyleng);
202 <Scan>[,= ;\t] { /* eat , so we have a nice separator in long initialization lines */
203 copyToOutput(yyscanner,yytext,(int)yyleng);
205 <Scan>"\"\"\""! { /* start of python long comment */
206 if (yyextra->lang!=SrcLangExt_Python)
212 yyextra->pythonDocString = TRUE;
213 yyextra->nestingCount=1;
214 clearCommentStack(yyscanner); /* to be on the save side */
215 copyToOutput(yyscanner,yytext,(int)yyleng);
217 yyextra->commentStack.push(yyextra->lineNr);
221 if (yyextra->lang!=SrcLangExt_Fortran)
227 copyToOutput(yyscanner,yytext,(int)yyleng);
228 yyextra->nestingCount=0; // Fortran doesn't have an end comment
229 clearCommentStack(yyscanner); /* to be on the save side */
231 yyextra->commentStack.push(yyextra->lineNr);
234 <Scan>[Cc\*][><!]/.*\n {
235 if (yyextra->lang!=SrcLangExt_Fortran)
241 /* check for fixed format; we might have some conditional as part of multiline if like C<5 .and. & */
242 if (yyextra->isFixedForm && (yyextra->col == 0))
244 copyToOutput(yyscanner,yytext,(int)yyleng);
245 yyextra->nestingCount=0; // Fortran doesn't have an end comment
246 clearCommentStack(yyscanner); /* to be on the save side */
248 yyextra->commentStack.push(yyextra->lineNr);
257 if (yyextra->lang!=SrcLangExt_Fortran)
263 copyToOutput(yyscanner,yytext,(int)yyleng);
267 if (yyextra->lang!=SrcLangExt_Fortran)
273 if (yyextra->col == 0)
275 copyToOutput(yyscanner,yytext,(int)yyleng);
283 <Scan>"\"" { /* start of a string */
284 copyToOutput(yyscanner,yytext,(int)yyleng);
285 yyextra->stringContext = YY_START;
289 copyToOutput(yyscanner,yytext,(int)yyleng);
290 yyextra->charContext = YY_START;
291 if (yyextra->lang!=SrcLangExt_VHDL)
296 <Scan>\n { /* new line */
297 copyToOutput(yyscanner,yytext,(int)yyleng);
299 <Scan>{CPPC}"!"/.*\n[ \t]*{CPPC}[\/!][^\/] | /* start C++ style special comment block */
300 <Scan>({CPPC}"/"[/]*)/[^/].*\n[ \t]*{CPPC}[\/!][^\/] { /* start C++ style special comment block */
301 if (yyextra->mlBrief)
303 REJECT; // bail out if we do not need to convert
310 while (i<(int)yyleng && yytext[i]=='/') i++;
312 yyextra->blockHeadCol=yyextra->col;
313 copyToOutput(yyscanner,"/**",3);
314 replaceAliases(yyscanner,QCString(yytext+i));
315 yyextra->inSpecialComment=TRUE;
317 yyextra->readLineCtx=SComment;
321 <Scan>{CPPC}"##Documentation"{ANYopt}/\n { /* Start of Rational Rose ANSI C++ comment block */
322 if (yyextra->mlBrief) REJECT;
323 int i=17; //=strlen("//##Documentation");
324 yyextra->blockHeadCol=yyextra->col;
325 copyToOutput(yyscanner,"/**",3);
326 replaceAliases(yyscanner,QCString(yytext+i));
327 yyextra->inRoseComment=TRUE;
330 <Scan>{CPPC}[!\/]/.*\n[ \t]*{CPPC}[|\/][ \t]*[@\\]"}" { // next line contains an end marker, see bug 752712
331 yyextra->inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
332 copyToOutput(yyscanner,yytext,(int)yyleng);
333 yyextra->readLineCtx=YY_START;
336 <Scan>{CPPC}/.*\n { /* one line C++ comment */
337 yyextra->inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
338 copyToOutput(yyscanner,yytext,(int)yyleng);
339 yyextra->readLineCtx=YY_START;
342 <Scan>{CCS}{CCE} { /* avoid matching next rule for empty C comment, see bug 711723 */
343 copyToOutput(yyscanner,yytext,(int)yyleng);
345 <Scan>{CCS}[*!]? { /* start of a C comment */
346 if (yyextra->lang==SrcLangExt_Python)
350 yyextra->specialComment=(int)yyleng==3;
351 yyextra->nestingCount=1;
352 clearCommentStack(yyscanner); /* to be on the save side */
353 copyToOutput(yyscanner,yytext,(int)yyleng);
354 if (yyextra->specialComment)
358 yyextra->commentStack.push(yyextra->lineNr);
361 if (yyextra->lang!=SrcLangExt_Python)
367 copyToOutput(yyscanner,yytext,(int)yyleng);
368 yyextra->nestingCount=0; // Python doesn't have an end comment for #
369 clearCommentStack(yyscanner); /* to be on the save side */
371 yyextra->commentStack.push(yyextra->lineNr);
374 <Scan>"--"[^!][^\n]* {
375 if (yyextra->lang!=SrcLangExt_VHDL)
381 copyToOutput(yyscanner,yytext,(int)yyleng);
385 if (yyextra->lang!=SrcLangExt_VHDL)
391 yyextra->vhdl = TRUE;
392 copyToOutput(yyscanner,yytext,(int)yyleng);
393 yyextra->nestingCount=0; // VHDL doesn't have an end comment
394 clearCommentStack(yyscanner); /* to be on the save side */
396 yyextra->commentStack.push(yyextra->lineNr);
400 if (yyextra->lang!=SrcLangExt_Fortran)
406 copyToOutput(yyscanner,yytext,(int)yyleng);
407 yyextra->nestingCount=0; // Fortran doesn't have an end comment
408 clearCommentStack(yyscanner); /* to be on the save side */
410 yyextra->commentStack.push(yyextra->lineNr);
413 <CComment,CNComment,ReadLine>{MAILADR} |
414 <CComment,CNComment,ReadLine>"<"{MAILADR}">" { // Mail address, to prevent seeing e.g x@code-factory.org as start of a code block
415 copyToOutput(yyscanner,yytext,(int)yyleng);
417 <CComment>"{"[ \t]*"@code"/[ \t\n] {
418 copyToOutput(yyscanner,"@code",5);
419 yyextra->lastCommentContext = YY_START;
420 yyextra->javaBlock=1;
421 yyextra->blockName=&yytext[1];
424 <CComment,ReadLine>^[ \t]*("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
425 if (!Config_getBool(MARKDOWN_SUPPORT))
429 copyToOutput(yyscanner,yytext,(int)yyleng);
430 yyextra->lastCommentContext = YY_START;
431 yyextra->javaBlock=0;
432 yyextra->blockName=QCString(yytext).stripWhiteSpace().left(3);
435 <CComment,ReadLine>[\\@]("dot"|"code"|"msc"|"startuml")/[^a-z_A-Z0-9] { /* start of a verbatim block */
436 copyToOutput(yyscanner,yytext,(int)yyleng);
437 yyextra->lastCommentContext = YY_START;
438 yyextra->javaBlock=0;
439 if (qstrcmp(&yytext[1],"startuml")==0)
441 yyextra->blockName="uml";
445 yyextra->blockName=&yytext[1];
449 <CComment,ReadLine>[\\@]("f$"|"f["|"f{"|"f(") {
450 copyToOutput(yyscanner,yytext,(int)yyleng);
451 yyextra->blockName=&yytext[1];
452 if (yyextra->blockName.at(1)=='[')
454 yyextra->blockName.at(1)=']';
456 else if (yyextra->blockName.at(1)=='{')
458 yyextra->blockName.at(1)='}';
460 else if (yyextra->blockName.at(1)=='(')
462 yyextra->blockName.at(1)=')';
464 yyextra->lastCommentContext = YY_START;
467 <CComment,ReadLine>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly")/[^a-z_A-Z0-9] { /* start of a verbatim block */
468 copyToOutput(yyscanner,yytext,(int)yyleng);
469 yyextra->blockName=&yytext[1];
470 yyextra->lastCommentContext = YY_START;
473 <Scan>"\\\"" { /* escaped double quote */
474 copyToOutput(yyscanner,yytext,(int)yyleng);
476 <Scan>"\\\\" { /* escaped backslash */
477 copyToOutput(yyscanner,yytext,(int)yyleng);
479 <Scan>. { /* any other character */
480 copyToOutput(yyscanner,yytext,(int)yyleng);
482 <Verbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}"|"f)") { /* end of verbatim block */
483 copyToOutput(yyscanner,yytext,(int)yyleng);
484 if (&yytext[1]==yyextra->blockName) // end of formula
486 BEGIN(yyextra->lastCommentContext);
488 else if (&yytext[4]==yyextra->blockName)
490 BEGIN(yyextra->lastCommentContext);
494 if (yyextra->javaBlock==0)
500 yyextra->javaBlock++;
501 copyToOutput(yyscanner,yytext,(int)yyleng);
505 if (yyextra->javaBlock==0)
511 yyextra->javaBlock--;
512 if (yyextra->javaBlock==0)
514 copyToOutput(yyscanner," @endcode ",10);
515 BEGIN(yyextra->lastCommentContext);
519 copyToOutput(yyscanner,yytext,(int)yyleng);
523 <VerbatimCode>("```"[`]*|"~~~"[~]*) { /* end of markdown code block */
524 copyToOutput(yyscanner,yytext,(int)yyleng);
525 if (yytext[0]==yyextra->blockName[0])
527 BEGIN(yyextra->lastCommentContext);
530 <VerbatimCode>[\\@]("enddot"|"endcode"|"endmsc"|"enduml") { /* end of verbatim block */
531 copyToOutput(yyscanner,yytext,(int)yyleng);
532 if (&yytext[4]==yyextra->blockName)
534 BEGIN(yyextra->lastCommentContext);
537 <VerbatimCode>^[ \t]*{CPPC}[\!\/]? { /* skip leading comments */
538 if (!yyextra->inSpecialComment)
540 copyToOutput(yyscanner,yytext,(int)yyleng);
545 while (yytext[l]==' ' || yytext[l]=='\t')
549 copyToOutput(yyscanner,yytext,l);
550 if (yyleng-l==3) // ends with //! or ///
552 copyToOutput(yyscanner," * ",3);
556 copyToOutput(yyscanner,"//",2);
560 <Verbatim,VerbatimCode>[^`~@\/\\\n{}]* { /* any character not a backslash or new line or } */
561 copyToOutput(yyscanner,yytext,(int)yyleng);
563 <Verbatim,VerbatimCode>\n { /* new line in verbatim block */
564 copyToOutput(yyscanner,yytext,(int)yyleng);
566 <Verbatim>^[ \t]*{CPPC}[/!] {
567 if (yyextra->blockName=="dot" || yyextra->blockName=="msc" || yyextra->blockName=="uml" || yyextra->blockName.at(0)=='f')
569 // see bug 487871, strip /// from dot images and formulas.
571 while (yytext[l]==' ' || yytext[l]=='\t')
575 copyToOutput(yyscanner,yytext,l);
576 copyToOutput(yyscanner," ",3);
578 else // even slashes are verbatim (e.g. \verbatim, \code)
583 <Verbatim,VerbatimCode>. { /* any other character */
584 copyToOutput(yyscanner,yytext,(int)yyleng);
586 <SkipString>\\. { /* escaped character in string */
587 if (yyextra->lang==SrcLangExt_Fortran || yyextra->lang==SrcLangExt_VHDL)
590 copyToOutput(yyscanner,yytext,1);
594 copyToOutput(yyscanner,yytext,(int)yyleng);
597 <SkipString>"\"" { /* end of string */
598 copyToOutput(yyscanner,yytext,(int)yyleng);
599 BEGIN(yyextra->stringContext);
601 <SkipString>. { /* any other string character */
602 copyToOutput(yyscanner,yytext,(int)yyleng);
604 <SkipString>\n { /* new line inside string (illegal for some compilers) */
605 copyToOutput(yyscanner,yytext,(int)yyleng);
607 <SkipChar>\\. { /* escaped character */
608 if (yyextra->lang==SrcLangExt_Fortran || yyextra->lang==SrcLangExt_VHDL)
611 copyToOutput(yyscanner,yytext,1);
615 copyToOutput(yyscanner,yytext,(int)yyleng);
618 <SkipChar>' { /* end of character literal */
619 copyToOutput(yyscanner,yytext,(int)yyleng);
620 BEGIN(yyextra->charContext);
622 <SkipChar>. { /* any other string character */
623 copyToOutput(yyscanner,yytext,(int)yyleng);
625 <SkipChar>\n { /* new line character */
626 copyToOutput(yyscanner,yytext,(int)yyleng);
629 <CComment,CNComment>[^ `~<\\!@*\n{\"\/]* { /* anything that is not a '*' or command */
630 copyToOutput(yyscanner,yytext,(int)yyleng);
632 <CComment,CNComment>"*"+[^*\/\\@\n{\"]* { /* stars without slashes */
633 copyToOutput(yyscanner,yytext,(int)yyleng);
635 <CComment>"\"\"\"" { /* end of Python docstring */
636 if (yyextra->lang!=SrcLangExt_Python)
642 yyextra->nestingCount--;
643 yyextra->pythonDocString = FALSE;
644 copyToOutput(yyscanner,yytext,(int)yyleng);
648 <CComment,CNComment>\n { /* new line in comment */
649 copyToOutput(yyscanner,yytext,(int)yyleng);
650 /* in case of Fortran always end of comment */
651 if (yyextra->lang==SrcLangExt_Fortran)
656 <CComment,CNComment>"/"+"*" { /* nested C comment */
657 if (yyextra->lang==SrcLangExt_Python ||
658 yyextra->lang==SrcLangExt_Markdown)
662 yyextra->nestingCount++;
663 yyextra->commentStack.push(yyextra->lineNr);
664 copyToOutput(yyscanner,yytext,(int)yyleng);
666 <CComment,CNComment>"*"+"/" { /* end of C comment */
667 if (yyextra->lang==SrcLangExt_Python ||
668 yyextra->lang==SrcLangExt_Markdown)
674 copyToOutput(yyscanner,yytext,(int)yyleng);
675 yyextra->nestingCount--;
676 if (yyextra->nestingCount<=0)
682 //yyextra->nestingCount--;
683 yyextra->commentStack.pop();
687 /* Python an VHDL share CComment,CNComment, so special attention for ending comments is required */
688 <CComment,CNComment>"\n"/[ \t]*"#" {
689 if (yyextra->lang!=SrcLangExt_VHDL)
695 if (yyextra->vhdl) // inside --! comment
697 yyextra->vhdl = FALSE;
698 copyToOutput(yyscanner,yytext,(int)yyleng);
701 else // C-type comment
707 <CComment,CNComment>"\n"/[ \t]*"-" {
708 if (yyextra->lang!=SrcLangExt_Python || yyextra->pythonDocString)
714 copyToOutput(yyscanner,yytext,(int)yyleng);
718 <CComment,CNComment>"\n"/[ \t]*[^ \t#\-] {
719 if (yyextra->lang==SrcLangExt_Python)
721 if (yyextra->pythonDocString)
727 copyToOutput(yyscanner,yytext,(int)yyleng);
731 else if (yyextra->lang==SrcLangExt_VHDL)
733 if (yyextra->vhdl) // inside --! comment
735 yyextra->vhdl = FALSE;
736 copyToOutput(yyscanner,yytext,(int)yyleng);
739 else // C-type comment
749 /* removed for bug 674842 (bug was introduced in rev 768)
750 <CComment,CNComment>"'" {
751 yyextra->charContext = YY_START;
752 copyToOutput(yyscanner,yytext,(int)yyleng);
755 <CComment,CNComment>"\"" {
756 yyextra->stringContext = YY_START;
757 copyToOutput(yyscanner,yytext,(int)yyleng);
761 <CComment,CNComment>. {
762 copyToOutput(yyscanner,yytext,(int)yyleng);
764 <SComment>^[ \t]*{CPPC}"/"{SLASHopt}/\n {
765 replaceComment(yyscanner,0);
767 <SComment>\n[ \t]*{CPPC}"/"{SLASHopt}/\n {
768 replaceComment(yyscanner,1);
770 <SComment>^[ \t]*{CPPC}"/"[^\/\n]/.*\n {
771 replaceComment(yyscanner,0);
772 yyextra->readLineCtx=YY_START;
775 <SComment>\n[ \t]*{CPPC}[\/!]("<")?[ \t]*[\\@]"}".*\n {
776 /* See Bug 752712: end the multiline comment when finding a @} or \} command */
777 copyToOutput(yyscanner," */",3);
778 copyToOutput(yyscanner,yytext,(int)yyleng);
779 yyextra->inSpecialComment=FALSE;
780 yyextra->inRoseComment=FALSE;
783 <SComment>\n[ \t]*{CPPC}"/"[^\/\n]/.*\n {
784 replaceComment(yyscanner,1);
785 yyextra->readLineCtx=YY_START;
788 <SComment>^[ \t]*{CPPC}"!" | // just //!
789 <SComment>^[ \t]*{CPPC}"!<"/.*\n | // or //!< something
790 <SComment>^[ \t]*{CPPC}"!"[^<]/.*\n { // or //!something
791 replaceComment(yyscanner,0);
792 yyextra->readLineCtx=YY_START;
795 <SComment>\n[ \t]*{CPPC}"!" |
796 <SComment>\n[ \t]*{CPPC}"!<"/.*\n |
797 <SComment>\n[ \t]*{CPPC}"!"[^<\n]/.*\n {
798 replaceComment(yyscanner,1);
799 yyextra->readLineCtx=YY_START;
802 <SComment>^[ \t]*{CPPC}"##"/.*\n {
803 if (!yyextra->inRoseComment)
809 replaceComment(yyscanner,0);
810 yyextra->readLineCtx=YY_START;
814 <SComment>\n[ \t]*{CPPC}"##"/.*\n {
815 if (!yyextra->inRoseComment)
821 replaceComment(yyscanner,1);
822 yyextra->readLineCtx=YY_START;
826 <SComment>\n { /* end of special comment */
827 copyToOutput(yyscanner," */",3);
828 copyToOutput(yyscanner,yytext,(int)yyleng);
829 yyextra->inSpecialComment=FALSE;
830 yyextra->inRoseComment=FALSE;
834 copyToOutput(yyscanner,"/‍**",8);
837 copyToOutput(yyscanner,"*‍/",7);
840 copyToOutput(yyscanner,yytext,(int)yyleng);
843 copyToOutput(yyscanner,yytext,(int)yyleng);
845 <ReadLine>{RLopt}/\n {
846 copyToOutput(yyscanner,yytext,(int)yyleng);
847 BEGIN(yyextra->readLineCtx);
849 <CComment,CNComment,ReadLine>[\\@][\\@][~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
850 copyToOutput(yyscanner,yytext,(int)yyleng);
852 <CComment,ReadLine>[\\@]"cond"/[^a-z_A-Z0-9] { // conditional section
853 yyextra->condCtx = YY_START;
856 <CComment,ReadLine>[\\@]"endcond"/[^a-z_A-Z0-9] { // end of conditional section
857 bool oldSkip=yyextra->skip;
858 endCondSection(yyscanner);
859 if (YY_START==CComment && oldSkip && !yyextra->skip)
861 //printf("** Adding start of comment!\n");
862 if (yyextra->lang!=SrcLangExt_Python &&
863 yyextra->lang!=SrcLangExt_VHDL &&
864 yyextra->lang!=SrcLangExt_Markdown &&
865 yyextra->lang!=SrcLangExt_Fortran)
869 if (yyextra->specialComment)
876 <CondLine>[!()&| \ta-z_A-Z0-9.\-]+ {
877 handleCondSectionId(yyscanner,yytext);
879 <CComment,ReadLine>[\\@]"cond"{WSopt}/\n {
880 yyextra->condCtx=YY_START;
881 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
883 <CondLine>. { // forgot section id?
884 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
885 if (*yytext=='\n') yyextra->lineNr++;
887 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias without arguments
888 replaceAliases(yyscanner,QCString(yytext));
890 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]*"{" { // expand alias with arguments
891 yyextra->lastBlockContext=YY_START;
892 yyextra->blockCount=1;
893 yyextra->aliasString=yytext;
894 yyextra->lastEscaped=0;
895 BEGIN( ReadAliasArgs );
897 <ReadAliasArgs>^[ \t]*{CPPC}[/!]/[^\n]+ { // skip leading special comments (see bug 618079)
899 <ReadAliasArgs>{CCE} { // oops, end of comment in the middle of an alias?
900 if (yyextra->lang==SrcLangExt_Python)
904 else // abort the alias, restart scanning
906 copyToOutput(yyscanner,yyextra->aliasString.data(),yyextra->aliasString.length());
907 copyToOutput(yyscanner,yytext,(int)yyleng);
911 <ReadAliasArgs>[^{}\n\\\*]+ {
912 yyextra->aliasString+=yytext;
913 yyextra->lastEscaped=FALSE;
915 <ReadAliasArgs>"\\" {
916 if (yyextra->lastEscaped) yyextra->lastEscaped=FALSE;
917 else yyextra->lastEscaped=TRUE;
918 yyextra->aliasString+=yytext;
921 yyextra->aliasString+=yytext;
923 yyextra->lastEscaped=FALSE;
926 yyextra->aliasString+=yytext;
927 if (!yyextra->lastEscaped) yyextra->blockCount++;
928 yyextra->lastEscaped=FALSE;
931 yyextra->aliasString+=yytext;
932 if (!yyextra->lastEscaped) yyextra->blockCount--;
933 if (yyextra->blockCount==0)
935 replaceAliases(yyscanner,yyextra->aliasString);
936 BEGIN( yyextra->lastBlockContext );
938 yyextra->lastEscaped=FALSE;
941 yyextra->aliasString+=yytext;
942 yyextra->lastEscaped=FALSE;
945 copyToOutput(yyscanner,yytext,(int)yyleng);
949 copyToOutput(yyscanner,yytext,(int)yyleng);
953 static void replaceCommentMarker(yyscan_t yyscanner,const char *s,int len)
955 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
958 // copy leading blanks
959 while ((c=*p) && (c==' ' || c=='\t' || c=='\n'))
962 yyextra->lineNr += c=='\n';
965 // replace start of comment marker by blanks and the last character by a *
967 while ((c=*p) && (c=='/' || c=='!' || c=='#'))
971 if (*p=='<') // comment-after-item marker
976 if (c=='!') // end after first !
988 if (blanks>1) ADDCHAR('*');
991 // copy comment line to output
992 ADDARRAY(p,len-(int)(p-s));
995 static inline int computeIndent(const char *s)
998 static int tabSize=Config_getInt(TAB_SIZE);
1004 else if (c=='\t') col+=tabSize-(col%tabSize);
1010 static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len)
1012 int tabSize=Config_getInt(TAB_SIZE);
1013 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1015 if (yyextra->skip) // only add newlines.
1027 yyextra->col+=tabSize-(yyextra->col%tabSize);
1042 case '\n': yyextra->col=0;
1043 //fprintf(stderr,"---> copy %d\n",g_lineNr);
1044 yyextra->lineNr++; break;
1045 case '\t': yyextra->col+=tabSize-(yyextra->col%tabSize); break;
1046 default: yyextra->col++; break;
1052 static void clearCommentStack(yyscan_t yyscanner)
1054 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1055 while (!yyextra->commentStack.empty()) yyextra->commentStack.pop();
1058 static void startCondSection(yyscan_t yyscanner,const QCString §Id)
1060 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1061 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1063 bool expResult = prs.parse(yyextra->fileName,yyextra->lineNr,sectId);
1064 yyextra->condStack.push(commentcnvYY_CondCtx(yyextra->lineNr,sectId,yyextra->skip));
1065 if (!expResult) // not enabled
1071 static void endCondSection(yyscan_t yyscanner)
1073 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1074 if (yyextra->condStack.empty())
1076 warn(yyextra->fileName,yyextra->lineNr,"Found \\endcond command without matching \\cond");
1077 yyextra->skip=FALSE;
1081 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
1082 yyextra->skip=ctx.skip;
1083 yyextra->condStack.pop();
1085 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1088 static void handleCondSectionId(yyscan_t yyscanner,const char *expression)
1090 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1091 bool oldSkip=yyextra->skip;
1092 startCondSection(yyscanner,QCString(expression));
1093 if ((yyextra->condCtx==CComment || yyextra->readLineCtx==SComment) &&
1094 !oldSkip && yyextra->skip)
1096 if (yyextra->lang!=SrcLangExt_Python &&
1097 yyextra->lang!=SrcLangExt_VHDL &&
1098 yyextra->lang!=SrcLangExt_Markdown &&
1099 yyextra->lang!=SrcLangExt_Fortran)
1105 if (yyextra->readLineCtx==SComment)
1111 BEGIN(yyextra->condCtx);
1115 /** copies string \a s with length \a len to the output, while
1116 * replacing any alias commands found in the string.
1118 static void replaceAliases(yyscan_t yyscanner,const QCString &s)
1120 QCString result = resolveAliasCmd(s);
1121 //printf("replaceAliases(%s)->'%s'\n",s,result.data());
1122 copyToOutput(yyscanner,result.data(),result.length());
1126 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
1128 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1129 yy_size_t bytesInBuf = yyextra->inBuf->curPos()-yyextra->inBufPos;
1130 yy_size_t bytesToCopy = std::min(max_size,bytesInBuf);
1131 memcpy(buf,yyextra->inBuf->data()+yyextra->inBufPos,bytesToCopy);
1132 yyextra->inBufPos+=bytesToCopy;
1136 static void replaceComment(yyscan_t yyscanner,int offset)
1138 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1139 if (yyextra->mlBrief || yyextra->skip)
1141 copyToOutput(yyscanner,yytext,(int)yyleng);
1145 //printf("replaceComment(%s)\n",yytext);
1146 int i=computeIndent(&yytext[offset]);
1147 if (i==yyextra->blockHeadCol)
1149 replaceCommentMarker(yyscanner,yytext,(int)yyleng);
1153 copyToOutput(yyscanner," */",3);
1154 for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
1155 yyextra->inSpecialComment=FALSE;
1161 /*! This function does three things:
1162 * -# It converts multi-line C++ style comment blocks (that are aligned)
1163 * to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
1164 * -# It replaces aliases with their definition (see ALIASES)
1165 * -# It handles conditional sections (cond...endcond blocks)
1167 void convertCppComments(BufStr *inBuf,BufStr *outBuf,const QCString &fileName)
1170 commentcnvYY_state extra;
1171 commentcnvYYlex_init_extra(&extra,&yyscanner);
1173 commentcnvYYset_debug(1,yyscanner);
1175 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1176 //printf("convertCppComments(%s)\n",fileName);
1177 yyextra->inBuf = inBuf;
1178 yyextra->outBuf = outBuf;
1179 yyextra->inBufPos = 0;
1181 yyextra->mlBrief = Config_getBool(MULTILINE_CPP_IS_BRIEF);
1182 yyextra->skip = FALSE;
1183 yyextra->fileName = fileName;
1184 yyextra->lang = getLanguageFromFileName(fileName);
1185 yyextra->pythonDocString = FALSE;
1186 yyextra->lineNr = 1;
1187 while (!yyextra->condStack.empty()) yyextra->condStack.pop();
1188 clearCommentStack(yyscanner);
1189 yyextra->vhdl = FALSE;
1191 printlex(yy_flex_debug, TRUE, __FILE__, qPrint(fileName));
1192 yyextra->isFixedForm = FALSE;
1193 if (yyextra->lang==SrcLangExt_Fortran)
1195 FortranFormat fmt = convertFileNameFortranParserCode(fileName);
1196 yyextra->isFixedForm = recognizeFixedForm(QCString(inBuf->data()),fmt);
1199 if (yyextra->lang==SrcLangExt_Markdown)
1201 yyextra->nestingCount=0;
1203 yyextra->commentStack.push(yyextra->lineNr);
1210 while (!yyextra->condStack.empty())
1212 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
1213 QCString sectionInfo(" ");
1214 if (ctx.sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",ctx.sectionId.stripWhiteSpace().data());
1215 warn(yyextra->fileName,ctx.lineNr,"Conditional section%sdoes not have "
1216 "a corresponding \\endcond command within this file.",sectionInfo.data());
1217 yyextra->condStack.pop();
1219 if (yyextra->nestingCount>0 && yyextra->lang!=SrcLangExt_Markdown && yyextra->lang!=SrcLangExt_Fortran)
1221 QCString tmp("(probable line reference: ");
1223 while (!yyextra->commentStack.empty())
1225 int lineNr = yyextra->commentStack.top();
1226 if (!first) tmp += ", ";
1227 tmp += QCString().setNum(lineNr);
1229 yyextra->commentStack.pop();
1232 warn(yyextra->fileName,yyextra->lineNr,"Reached end of file while still inside a (nested) comment. "
1233 "Nesting level %d %s",yyextra->nestingCount,tmp.data());
1235 yyextra->nestingCount = 0;
1236 if (Debug::isFlagSet(Debug::CommentCnv))
1238 yyextra->outBuf->at(yyextra->outBuf->curPos())='\0';
1239 Debug::print(Debug::CommentCnv,0,"-----------\nCommentCnv: %s\n"
1240 "output=[\n%s]\n-----------\n",qPrint(fileName),yyextra->outBuf->data()
1243 printlex(yy_flex_debug, FALSE, __FILE__, qPrint(fileName));
1244 commentcnvYYlex_destroy(yyscanner);
1248 //----------------------------------------------------------------------------
1250 #if USE_STATE2STRING
1251 #include "commentcnv.l.h"