1 /*****************************************************************************
3 * Copyright (C) 1997-2023 by Dimitri van Heesch.
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
15 %option never-interactive
16 %option prefix="commentcnvYY"
18 %option extra-type="struct commentcnvYY_state *"
21 // forward declare yyscan_t to improve type safety
22 #define YY_TYPEDEF_YY_SCANNER_T
24 typedef yyguts_t *yyscan_t;
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
54 struct commentcnvYY_CondCtx
56 commentcnvYY_CondCtx(int line,const QCString &id,bool b)
57 : lineNr(line),sectionId(id), skip(b) {}
70 struct commentcnvYY_state
72 commentcnvYY_state(const BufStr &i,BufStr &o) : inBuf(i), outBuf(o) {}
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 int yyread(yyscan_t yyscanner,char *buf,int 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);
129 // otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
130 static inline const char *getLexerFILE() {return __FILE__;}
131 #include "doxygen_lex.h"
135 MAILADDR ("mailto:")?[a-z_A-Z0-9\x80-\xff.+-]+"@"[a-z_A-Z0-9\x80-\xff-]+("."[a-z_A-Z0-9\x80-\xff\-]+)+[a-z_A-Z0-9\x80-\xff\-]+
151 //- start: NUMBER -------------------------------------------------------------------------
152 // Note same defines in code.l: keep in sync
153 DECIMAL_INTEGER [1-9][0-9']*[0-9]?[uU]?[lL]?[lL]?
154 HEXADECIMAL_INTEGER "0"[xX][0-9a-zA-Z']+[0-9a-zA-Z]?
155 OCTAL_INTEGER "0"[0-7][0-7']+[0-7]?
156 BINARY_INTEGER "0"[bB][01][01']*[01]?
157 INTEGER_NUMBER {DECIMAL_INTEGER}|{HEXADECIMAL_INTEGER}|{OCTAL_INTEGER}|{BINARY_INTEGER}
161 DIGIT_SEQ [0-9][0-9']*[0-9]?
162 FRAC_CONST {DIGIT_SEQ}"."|{DIGIT_SEQ}?"."{DIGIT_SEQ}
163 FP_EXP [eE][+-]?{DIGIT_SEQ}
164 DEC_FP1 {FRAC_CONST}{FP_EXP}?{FP_SUF}?
165 DEC_FP2 {DIGIT_SEQ}{FP_EXP}{FP_SUF}
167 HEX_DIGIT_SEQ [0-9a-fA-F][0-9a-fA-F']*[0-9a-fA-F]?
168 HEX_FRAC_CONST {HEX_DIGIT_SEQ}"."|{HEX_DIGIT_SEQ}?"."{HEX_DIGIT_SEQ}
169 BIN_EXP [pP][+-]?{DIGIT_SEQ}
170 HEX_FP1 "0"[xX]{HEX_FRAC_CONST}{BIN_EXP}{FP_SUF}?
171 HEX_FP2 "0"[xX]{HEX_DIGIT_SEQ}{BIN_EXP}{FP_SUF}?
173 FLOAT_DECIMAL {DEC_FP1}|{DEC_FP2}
174 FLOAT_HEXADECIMAL {HEX_FP1}|{HEX_FP2}
175 FLOAT_NUMBER {FLOAT_DECIMAL}|{FLOAT_HEXADECIMAL}
176 NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
177 //- end: NUMBER ---------------------------------------------------------------------------
186 // Optional any character
189 // Optional white space
191 // readline non special
198 <Scan>{NUMBER} { //Note similar code in code.l
199 if (yyextra->lang!=SrcLangExt_Cpp) REJECT;
200 copyToOutput(yyscanner,yytext,(int)yyleng);
202 <Scan>[^"'!\/\n\\#,\-=; \t]* { /* eat anything that is not " / , or \n */
203 copyToOutput(yyscanner,yytext,(int)yyleng);
205 <Scan>[,= ;\t] { /* eat , so we have a nice separator in long initialization lines */
206 copyToOutput(yyscanner,yytext,(int)yyleng);
208 <Scan>"\"\"\""! { /* start of python long comment */
209 if (yyextra->lang!=SrcLangExt_Python)
215 yyextra->pythonDocString = TRUE;
216 yyextra->nestingCount=1;
217 clearCommentStack(yyscanner); /* to be on the save side */
218 copyToOutput(yyscanner,yytext,(int)yyleng);
220 yyextra->commentStack.push(yyextra->lineNr);
223 <Scan>"\"\"\"" { /* start of python long comment */
224 if (yyextra->lang!=SrcLangExt_Python)
228 else if (Config_getBool(PYTHON_DOCSTRING))
233 { /* handle as if """! */
234 yyextra->pythonDocString = TRUE;
235 yyextra->nestingCount=1;
236 clearCommentStack(yyscanner); /* to be on the save side */
237 copyToOutput(yyscanner,yytext,(int)yyleng);
239 yyextra->commentStack.push(yyextra->lineNr);
243 if (yyextra->lang!=SrcLangExt_Fortran)
249 copyToOutput(yyscanner,yytext,(int)yyleng);
250 yyextra->nestingCount=0; // Fortran doesn't have an end comment
251 clearCommentStack(yyscanner); /* to be on the save side */
253 yyextra->commentStack.push(yyextra->lineNr);
256 <Scan>[Cc\*][><!]/.*\n {
257 if (yyextra->lang!=SrcLangExt_Fortran)
263 /* check for fixed format; we might have some conditional as part of multiline if like C<5 .and. & */
264 if (yyextra->isFixedForm && (yyextra->col == 0))
266 copyToOutput(yyscanner,yytext,(int)yyleng);
267 yyextra->nestingCount=0; // Fortran doesn't have an end comment
268 clearCommentStack(yyscanner); /* to be on the save side */
270 yyextra->commentStack.push(yyextra->lineNr);
279 if (yyextra->lang!=SrcLangExt_Fortran)
285 copyToOutput(yyscanner,yytext,(int)yyleng);
289 if (yyextra->lang!=SrcLangExt_Fortran)
295 if (yyextra->col == 0)
297 copyToOutput(yyscanner,yytext,(int)yyleng);
305 <Scan>"\"" { /* start of a string */
306 copyToOutput(yyscanner,yytext,(int)yyleng);
307 yyextra->stringContext = YY_START;
311 copyToOutput(yyscanner,yytext,(int)yyleng);
312 yyextra->charContext = YY_START;
313 if (yyextra->lang!=SrcLangExt_VHDL)
318 <Scan>\n { /* new line */
319 copyToOutput(yyscanner,yytext,(int)yyleng);
321 <Scan>{CPPC}"!"/.*\n[ \t]*{CPPC}[\/!][^\/] | /* start C++ style special comment block */
322 <Scan>({CPPC}"/"[/]*)/[^/].*\n[ \t]*{CPPC}[\/!][^\/] { /* start C++ style special comment block */
323 if (yyextra->mlBrief)
325 REJECT; // bail out if we do not need to convert
332 while (i<(int)yyleng && yytext[i]=='/') i++;
334 yyextra->blockHeadCol=yyextra->col;
335 copyToOutput(yyscanner,"/**",3);
336 replaceAliases(yyscanner,QCString(yytext+i));
337 yyextra->inSpecialComment=TRUE;
339 yyextra->readLineCtx=SComment;
343 <Scan>{CPPC}"##Documentation"{ANYopt}/\n { /* Start of Rational Rose ANSI C++ comment block */
344 if (yyextra->mlBrief) REJECT;
345 int i=17; //=strlen("//##Documentation");
346 yyextra->blockHeadCol=yyextra->col;
347 copyToOutput(yyscanner,"/**",3);
348 replaceAliases(yyscanner,QCString(yytext+i));
349 yyextra->inRoseComment=TRUE;
352 <Scan>{CPPC}[!\/]/.*\n[ \t]*{CPPC}[|\/][ \t]*[@\\]"}" { // next line contains an end marker, see bug 752712
353 yyextra->inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
354 copyToOutput(yyscanner,yytext,(int)yyleng);
355 yyextra->readLineCtx=YY_START;
358 <Scan>{CPPC}/.*\n { /* one line C++ comment */
359 yyextra->inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
360 copyToOutput(yyscanner,yytext,(int)yyleng);
361 yyextra->readLineCtx=YY_START;
364 <Scan>{CCS}{CCE} { /* avoid matching next rule for empty C comment, see bug 711723 */
365 copyToOutput(yyscanner,yytext,(int)yyleng);
367 <Scan>{CCS}[*!]? { /* start of a C comment */
368 if (yyextra->lang==SrcLangExt_Python)
372 yyextra->specialComment=(int)yyleng==3;
373 yyextra->nestingCount=1;
374 clearCommentStack(yyscanner); /* to be on the save side */
375 copyToOutput(yyscanner,yytext,(int)yyleng);
376 if (yyextra->specialComment)
380 yyextra->commentStack.push(yyextra->lineNr);
383 if (yyextra->lang!=SrcLangExt_PHP)
387 copyToOutput(yyscanner,yytext,(int)yyleng);
390 if (yyextra->lang!=SrcLangExt_Python)
396 copyToOutput(yyscanner,yytext,(int)yyleng);
397 yyextra->nestingCount=0; // Python doesn't have an end comment for #
398 clearCommentStack(yyscanner); /* to be on the save side */
400 yyextra->commentStack.push(yyextra->lineNr);
403 <Scan>"--"[^!][^\n]* {
404 if (yyextra->lang!=SrcLangExt_VHDL)
410 copyToOutput(yyscanner,yytext,(int)yyleng);
414 if (yyextra->lang!=SrcLangExt_VHDL)
420 yyextra->vhdl = TRUE;
421 copyToOutput(yyscanner,yytext,(int)yyleng);
422 yyextra->nestingCount=0; // VHDL doesn't have an end comment
423 clearCommentStack(yyscanner); /* to be on the save side */
425 yyextra->commentStack.push(yyextra->lineNr);
429 if (yyextra->lang!=SrcLangExt_Fortran)
435 copyToOutput(yyscanner,yytext,(int)yyleng);
436 yyextra->nestingCount=0; // Fortran doesn't have an end comment
437 clearCommentStack(yyscanner); /* to be on the save side */
439 yyextra->commentStack.push(yyextra->lineNr);
442 <CComment,CNComment,ReadLine>{MAILADDR} |
443 <CComment,CNComment,ReadLine>"<"{MAILADDR}">" { // Mail address, to prevent seeing e.g x@code-factory.org as start of a code block
444 copyToOutput(yyscanner,yytext,(int)yyleng);
446 <CComment>"{"[ \t]*"@code"/[ \t\n] {
447 copyToOutput(yyscanner,"@iliteral{code}",15);
448 yyextra->lastCommentContext = YY_START;
449 yyextra->javaBlock=1;
450 yyextra->blockName=&yytext[1];
453 <CComment>"{"[ \t]*"@literal"/[ \t\n] {
454 copyToOutput(yyscanner,"@iliteral",9);
455 yyextra->lastCommentContext = YY_START;
456 yyextra->javaBlock=1;
457 yyextra->blockName=&yytext[1];
460 <CComment,ReadLine>^[ \t]*("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
461 if (!Config_getBool(MARKDOWN_SUPPORT))
465 copyToOutput(yyscanner,yytext,(int)yyleng);
466 yyextra->lastCommentContext = YY_START;
467 yyextra->javaBlock=0;
468 yyextra->blockName=QCString(yytext).stripWhiteSpace().left(3); // take the ``` or ~~~ part
471 <CComment,ReadLine>[\\@]("dot"|"code"|"msc"|"startuml")/[^a-z_A-Z0-9] { /* start of a verbatim block */
472 copyToOutput(yyscanner,yytext,(int)yyleng);
473 yyextra->lastCommentContext = YY_START;
474 yyextra->javaBlock=0;
475 if (qstrcmp(&yytext[1],"startuml")==0)
477 yyextra->blockName="uml";
481 yyextra->blockName=&yytext[1];
485 <CComment,ReadLine>[\\@]("f$"|"f["|"f{"|"f(") {
486 copyToOutput(yyscanner,yytext,(int)yyleng);
487 yyextra->blockName=&yytext[1];
488 if (yyextra->blockName.at(1)=='[')
490 yyextra->blockName.at(1)=']';
492 else if (yyextra->blockName.at(1)=='{')
494 yyextra->blockName.at(1)='}';
496 else if (yyextra->blockName.at(1)=='(')
498 yyextra->blockName.at(1)=')';
500 yyextra->lastCommentContext = YY_START;
503 <CComment,ReadLine>[\\@]("verbatim"|"iliteral"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly")/[^a-z_A-Z0-9] { /* start of a verbatim block */
504 copyToOutput(yyscanner,yytext,(int)yyleng);
505 yyextra->blockName=&yytext[1];
506 yyextra->lastCommentContext = YY_START;
509 <Scan>"\\\"" { /* escaped double quote */
510 copyToOutput(yyscanner,yytext,(int)yyleng);
512 <Scan>"\\\\" { /* escaped backslash */
513 copyToOutput(yyscanner,yytext,(int)yyleng);
515 <Scan>. { /* any other character */
516 copyToOutput(yyscanner,yytext,(int)yyleng);
518 <Verbatim>[\\@]("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}"|"f)") { /* end of verbatim block */
519 copyToOutput(yyscanner,yytext,(int)yyleng);
520 if (&yytext[1]==yyextra->blockName) // end of formula
522 BEGIN(yyextra->lastCommentContext);
524 else if (&yytext[4]==yyextra->blockName)
526 BEGIN(yyextra->lastCommentContext);
530 if (yyextra->javaBlock==0)
536 yyextra->javaBlock++;
537 copyToOutput(yyscanner,yytext,(int)yyleng);
541 if (yyextra->javaBlock==0)
547 yyextra->javaBlock--;
548 if (yyextra->javaBlock==0)
550 copyToOutput(yyscanner," @endiliteral ",14);
551 BEGIN(yyextra->lastCommentContext);
555 copyToOutput(yyscanner,yytext,(int)yyleng);
559 <VerbatimCode>("```"[`]*|"~~~"[~]*) { /* end of markdown code block */
560 copyToOutput(yyscanner,yytext,(int)yyleng);
561 if (yytext[0]==yyextra->blockName[0])
563 BEGIN(yyextra->lastCommentContext);
566 <VerbatimCode>[\\@]("enddot"|"endcode"|"endmsc"|"enduml") { /* end of verbatim block */
567 copyToOutput(yyscanner,yytext,(int)yyleng);
568 if (&yytext[4]==yyextra->blockName)
570 BEGIN(yyextra->lastCommentContext);
573 <VerbatimCode>^[ \t]*{CPPC}[\!\/]? { /* skip leading comments */
574 if (!yyextra->inSpecialComment)
576 copyToOutput(yyscanner,yytext,(int)yyleng);
581 while (yytext[l]==' ' || yytext[l]=='\t')
585 copyToOutput(yyscanner,yytext,l);
586 if (yyleng-l==3) // ends with //! or ///
588 copyToOutput(yyscanner," * ",3);
592 copyToOutput(yyscanner,"//",2);
596 <Verbatim,VerbatimCode>[^`~@\/\\\n{}]* { /* any character not a backslash or new line or } */
597 copyToOutput(yyscanner,yytext,(int)yyleng);
599 <Verbatim,VerbatimCode>\n { /* new line in verbatim block */
600 copyToOutput(yyscanner,yytext,(int)yyleng);
602 <Verbatim>^[ \t]*{CPPC}[/!] {
603 if (yyextra->blockName=="dot" || yyextra->blockName=="msc" || yyextra->blockName=="uml" || yyextra->blockName.at(0)=='f')
605 // see bug 487871, strip /// from dot images and formulas.
607 while (yytext[l]==' ' || yytext[l]=='\t')
611 copyToOutput(yyscanner,yytext,l);
612 copyToOutput(yyscanner," ",3);
614 else // even slashes are verbatim (e.g. \verbatim, \code)
619 <Verbatim,VerbatimCode>. { /* any other character */
620 copyToOutput(yyscanner,yytext,(int)yyleng);
622 <SkipString>\\. { /* escaped character in string */
623 if (yyextra->lang==SrcLangExt_Fortran || yyextra->lang==SrcLangExt_VHDL)
626 copyToOutput(yyscanner,yytext,1);
630 copyToOutput(yyscanner,yytext,(int)yyleng);
633 <SkipString>"\"" { /* end of string */
634 copyToOutput(yyscanner,yytext,(int)yyleng);
635 BEGIN(yyextra->stringContext);
637 <SkipString>. { /* any other string character */
638 copyToOutput(yyscanner,yytext,(int)yyleng);
640 <SkipString>\n { /* new line inside string (illegal for some compilers) */
641 copyToOutput(yyscanner,yytext,(int)yyleng);
643 <SkipChar>\\. { /* escaped character */
644 if (yyextra->lang==SrcLangExt_Fortran || yyextra->lang==SrcLangExt_VHDL)
647 copyToOutput(yyscanner,yytext,1);
651 copyToOutput(yyscanner,yytext,(int)yyleng);
654 <SkipChar>' { /* end of character literal */
655 copyToOutput(yyscanner,yytext,(int)yyleng);
656 BEGIN(yyextra->charContext);
658 <SkipChar>. { /* any other string character */
659 copyToOutput(yyscanner,yytext,(int)yyleng);
661 <SkipChar>\n { /* new line character */
662 copyToOutput(yyscanner,yytext,(int)yyleng);
665 <CComment,CNComment>[^ `~<\\!@*\n{\"\/]* { /* anything that is not a '*' or command */
666 copyToOutput(yyscanner,yytext,(int)yyleng);
668 <CComment,CNComment>"*"+[^*\/\\@\n{\"]* { /* stars without slashes */
669 copyToOutput(yyscanner,yytext,(int)yyleng);
671 <CComment>"\"\"\"" { /* end of Python docstring */
672 if (yyextra->lang!=SrcLangExt_Python)
678 yyextra->nestingCount--;
679 yyextra->pythonDocString = FALSE;
680 copyToOutput(yyscanner,yytext,(int)yyleng);
684 <CComment,CNComment>\n { /* new line in comment */
685 copyToOutput(yyscanner,yytext,(int)yyleng);
686 /* in case of Fortran always end of comment */
687 if (yyextra->lang==SrcLangExt_Fortran)
692 <CComment,CNComment>"/""/"+/"*/" { /* we are already in C-comment so not a start of a nested comment but
693 * just the end of the comment (the end part is handled later). */
694 copyToOutput(yyscanner,yytext,(int)yyleng);
696 <CComment,CNComment>"/"+"*" { /* nested C comment */
697 if (yyextra->lang==SrcLangExt_Python ||
698 yyextra->lang==SrcLangExt_Markdown)
702 yyextra->nestingCount++;
703 yyextra->commentStack.push(yyextra->lineNr);
704 copyToOutput(yyscanner,yytext,(int)yyleng);
706 <CComment,CNComment>"*"+"/" { /* end of C comment */
707 if (yyextra->lang==SrcLangExt_Python ||
708 yyextra->lang==SrcLangExt_Markdown)
714 copyToOutput(yyscanner,yytext,(int)yyleng);
715 yyextra->nestingCount--;
716 if (yyextra->nestingCount<=0)
722 //yyextra->nestingCount--;
723 yyextra->commentStack.pop();
727 /* Python an VHDL share CComment,CNComment, so special attention for ending comments is required */
728 <CComment,CNComment>"\n"/[ \t]*"#" {
729 if (yyextra->lang!=SrcLangExt_VHDL)
735 if (yyextra->vhdl) // inside --! comment
737 yyextra->vhdl = FALSE;
738 copyToOutput(yyscanner,yytext,(int)yyleng);
741 else // C-type comment
747 <CComment,CNComment>"\n"/[ \t]*"-" {
748 if (yyextra->lang!=SrcLangExt_Python || yyextra->pythonDocString)
754 copyToOutput(yyscanner,yytext,(int)yyleng);
758 <CComment,CNComment>"\n"/[ \t]*[^ \t#\-] {
759 if (yyextra->lang==SrcLangExt_Python)
761 if (yyextra->pythonDocString)
767 copyToOutput(yyscanner,yytext,(int)yyleng);
771 else if (yyextra->lang==SrcLangExt_VHDL)
773 if (yyextra->vhdl) // inside --! comment
775 yyextra->vhdl = FALSE;
776 copyToOutput(yyscanner,yytext,(int)yyleng);
779 else // C-type comment
789 /* removed for bug 674842 (bug was introduced in rev 768)
790 <CComment,CNComment>"'" {
791 yyextra->charContext = YY_START;
792 copyToOutput(yyscanner,yytext,(int)yyleng);
795 <CComment,CNComment>"\"" {
796 yyextra->stringContext = YY_START;
797 copyToOutput(yyscanner,yytext,(int)yyleng);
801 <CComment,CNComment>. {
802 copyToOutput(yyscanner,yytext,(int)yyleng);
804 <SComment>^[ \t]*{CPPC}"/"{SLASHopt}/\n {
805 replaceComment(yyscanner,0);
807 <SComment>\n[ \t]*{CPPC}"/"{SLASHopt}/\n {
808 replaceComment(yyscanner,1);
810 <SComment>^[ \t]*{CPPC}"/"[^\/\n]/.*\n {
811 replaceComment(yyscanner,0);
812 yyextra->readLineCtx=YY_START;
815 <SComment>\n[ \t]*{CPPC}[\/!]("<")?[ \t]*[\\@]"}".*\n {
816 /* See Bug 752712: end the multiline comment when finding a @} or \} command */
817 copyToOutput(yyscanner," */",3);
818 copyToOutput(yyscanner,yytext,(int)yyleng);
819 yyextra->inSpecialComment=FALSE;
820 yyextra->inRoseComment=FALSE;
823 <SComment>\n[ \t]*{CPPC}"/"[^\/\n]/.*\n {
824 replaceComment(yyscanner,1);
825 yyextra->readLineCtx=YY_START;
828 <SComment>^[ \t]*{CPPC}"!" | // just //!
829 <SComment>^[ \t]*{CPPC}"!<"/.*\n | // or //!< something
830 <SComment>^[ \t]*{CPPC}"!"[^<]/.*\n { // or //!something
831 replaceComment(yyscanner,0);
832 yyextra->readLineCtx=YY_START;
835 <SComment>\n[ \t]*{CPPC}"!" |
836 <SComment>\n[ \t]*{CPPC}"!<"/.*\n |
837 <SComment>\n[ \t]*{CPPC}"!"[^<\n]/.*\n {
838 replaceComment(yyscanner,1);
839 yyextra->readLineCtx=YY_START;
842 <SComment>^[ \t]*{CPPC}"##"/.*\n {
843 if (!yyextra->inRoseComment)
849 replaceComment(yyscanner,0);
850 yyextra->readLineCtx=YY_START;
854 <SComment>\n[ \t]*{CPPC}"##"/.*\n {
855 if (!yyextra->inRoseComment)
861 replaceComment(yyscanner,1);
862 yyextra->readLineCtx=YY_START;
866 <SComment>\n { /* end of special comment */
867 copyToOutput(yyscanner," */",3);
868 copyToOutput(yyscanner,yytext,(int)yyleng);
869 yyextra->inSpecialComment=FALSE;
870 yyextra->inRoseComment=FALSE;
871 yyextra->readLineCtx = Scan; // reset, otherwise there will be problems with:
872 // static void handleCondSectionId
876 copyToOutput(yyscanner,"/‍**",8);
879 copyToOutput(yyscanner,"*‍/",7);
882 copyToOutput(yyscanner,yytext,(int)yyleng);
885 copyToOutput(yyscanner,yytext,(int)yyleng);
887 <ReadLine>{RLopt}/\n {
888 copyToOutput(yyscanner,yytext,(int)yyleng);
889 BEGIN(yyextra->readLineCtx);
891 <CComment,CNComment,ReadLine>[\\@][\\@][~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
892 copyToOutput(yyscanner,yytext,(int)yyleng);
894 <CComment,ReadLine>[\\@]"cond"/[^a-z_A-Z0-9] { // conditional section
895 yyextra->condCtx = YY_START;
898 <CComment,ReadLine>[\\@]"endcond"/[^a-z_A-Z0-9] { // end of conditional section
899 bool oldSkip=yyextra->skip;
900 endCondSection(yyscanner);
901 if (YY_START==CComment && oldSkip && !yyextra->skip)
903 //printf("** Adding start of comment!\n");
904 if (yyextra->lang!=SrcLangExt_Python &&
905 yyextra->lang!=SrcLangExt_VHDL &&
906 yyextra->lang!=SrcLangExt_Markdown &&
907 yyextra->lang!=SrcLangExt_Fortran)
911 if (yyextra->specialComment)
918 <CondLine>[!()&| \ta-z_A-Z0-9.\-]+ {
919 handleCondSectionId(yyscanner,yytext);
921 <CComment,ReadLine>[\\@]"cond"{WSopt}/\n {
922 yyextra->condCtx=YY_START;
923 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
926 <CondLine>. { // forgot section id?
927 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
928 if (*yytext=='\n') { yyextra->lineNr++; copyToOutput(yyscanner,"\n",1);}
930 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9-]* { // expand alias without arguments
931 replaceAliases(yyscanner,QCString(yytext));
933 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9-]*"{" { // expand alias with arguments
934 yyextra->lastBlockContext=YY_START;
935 yyextra->blockCount=1;
936 yyextra->aliasString=yytext;
937 yyextra->lastEscaped=0;
938 BEGIN( ReadAliasArgs );
940 <ReadAliasArgs>^[ \t]*{CPPC}[/!]/[^\n]+ { // skip leading special comments (see bug 618079)
942 <ReadAliasArgs>{CCE} { // oops, end of comment in the middle of an alias?
943 if (yyextra->lang==SrcLangExt_Python)
947 else // abort the alias, restart scanning
949 copyToOutput(yyscanner,yyextra->aliasString.data(),yyextra->aliasString.length());
950 copyToOutput(yyscanner,yytext,(int)yyleng);
954 <ReadAliasArgs>[^{}\n\\\*]+ {
955 yyextra->aliasString+=yytext;
956 yyextra->lastEscaped=FALSE;
958 <ReadAliasArgs>"\\" {
959 if (yyextra->lastEscaped) yyextra->lastEscaped=FALSE;
960 else yyextra->lastEscaped=TRUE;
961 yyextra->aliasString+=yytext;
964 yyextra->aliasString+=yytext;
966 yyextra->lastEscaped=FALSE;
969 yyextra->aliasString+=yytext;
970 if (!yyextra->lastEscaped) yyextra->blockCount++;
971 yyextra->lastEscaped=FALSE;
974 yyextra->aliasString+=yytext;
975 if (!yyextra->lastEscaped) yyextra->blockCount--;
976 if (yyextra->blockCount==0)
978 replaceAliases(yyscanner,yyextra->aliasString);
979 BEGIN( yyextra->lastBlockContext );
981 yyextra->lastEscaped=FALSE;
984 yyextra->aliasString+=yytext;
985 yyextra->lastEscaped=FALSE;
988 copyToOutput(yyscanner,yytext,(int)yyleng);
992 copyToOutput(yyscanner,yytext,(int)yyleng);
995 <*>\n { fprintf(stderr,"Lex scanner %s (%s) default rule newline for state %s.\n", __FILE__, qPrint(yyextra->fileName),stateToString(YY_START));}
999 static void replaceCommentMarker(yyscan_t yyscanner,const char *s,int len)
1001 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1004 // copy leading blanks
1005 while ((c=*p) && (c==' ' || c=='\t' || c=='\n'))
1008 yyextra->lineNr += c=='\n';
1011 // replace start of comment marker by blanks and the last character by a *
1013 while ((c=*p) && (c=='/' || c=='!' || c=='#'))
1017 if (*p=='<') // comment-after-item marker
1022 if (c=='!') // end after first !
1034 if (blanks>1) ADDCHAR('*');
1037 // copy comment line to output
1038 ADDARRAY(p,len-(int)(p-s));
1041 static inline int computeIndent(const char *s)
1044 int tabSize=Config_getInt(TAB_SIZE);
1050 else if (c=='\t') col+=tabSize-(col%tabSize);
1056 static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len)
1058 int tabSize=Config_getInt(TAB_SIZE);
1059 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1061 if (yyextra->skip) // only add newlines.
1073 yyextra->col+=tabSize-(yyextra->col%tabSize);
1088 case '\n': yyextra->col=0;
1089 //fprintf(stderr,"---> copy %d\n",g_lineNr);
1090 yyextra->lineNr++; break;
1091 case '\t': yyextra->col+=tabSize-(yyextra->col%tabSize); break;
1092 default: yyextra->col++; break;
1098 static void clearCommentStack(yyscan_t yyscanner)
1100 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1101 while (!yyextra->commentStack.empty()) yyextra->commentStack.pop();
1104 static void startCondSection(yyscan_t yyscanner,const QCString §Id)
1106 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1107 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1109 bool expResult = prs.parse(yyextra->fileName,yyextra->lineNr,sectId);
1110 yyextra->condStack.push(commentcnvYY_CondCtx(yyextra->lineNr,sectId,yyextra->skip));
1111 if (!expResult) // not enabled
1117 static void endCondSection(yyscan_t yyscanner)
1119 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1120 if (yyextra->condStack.empty())
1122 warn(yyextra->fileName,yyextra->lineNr,"Found \\endcond command without matching \\cond");
1123 yyextra->skip=FALSE;
1127 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
1128 yyextra->skip=ctx.skip;
1129 yyextra->condStack.pop();
1131 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1134 static void handleCondSectionId(yyscan_t yyscanner,const char *expression)
1136 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1137 bool oldSkip=yyextra->skip;
1138 startCondSection(yyscanner,QCString(expression));
1139 if ((yyextra->condCtx==CComment || yyextra->readLineCtx==SComment) &&
1140 !oldSkip && yyextra->skip)
1142 if (yyextra->lang!=SrcLangExt_Python &&
1143 yyextra->lang!=SrcLangExt_VHDL &&
1144 yyextra->lang!=SrcLangExt_Markdown &&
1145 yyextra->lang!=SrcLangExt_Fortran)
1151 if (yyextra->readLineCtx==SComment)
1157 BEGIN(yyextra->condCtx);
1161 /** copies string \a s with length \a len to the output, while
1162 * replacing any alias commands found in the string.
1164 static void replaceAliases(yyscan_t yyscanner,const QCString &s)
1166 QCString result = resolveAliasCmd(s);
1167 //printf("replaceAliases(%s)->'%s'\n",qPrint(s),qPrint(result));
1168 copyToOutput(yyscanner,result.data(),result.length());
1172 static int yyread(yyscan_t yyscanner,char *buf,int max_size)
1174 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1175 int bytesInBuf = static_cast<int>(yyextra->inBuf.curPos())-yyextra->inBufPos;
1176 int bytesToCopy = std::min(max_size,bytesInBuf);
1177 memcpy(buf,yyextra->inBuf.data()+yyextra->inBufPos,bytesToCopy);
1178 yyextra->inBufPos+=bytesToCopy;
1182 static void replaceComment(yyscan_t yyscanner,int offset)
1184 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1185 if (yyextra->mlBrief || yyextra->skip)
1187 copyToOutput(yyscanner,yytext,(int)yyleng);
1191 //printf("replaceComment(%s)\n",yytext);
1192 int i=computeIndent(&yytext[offset]);
1193 if (i==yyextra->blockHeadCol)
1195 replaceCommentMarker(yyscanner,yytext,(int)yyleng);
1199 copyToOutput(yyscanner," */",3);
1200 for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
1201 yyextra->inSpecialComment=FALSE;
1207 /*! This function does three things:
1208 * -# It converts multi-line C++ style comment blocks (that are aligned)
1209 * to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
1210 * -# It replaces aliases with their definition (see ALIASES)
1211 * -# It handles conditional sections (cond...endcond blocks)
1213 void convertCppComments(const BufStr &inBuf,BufStr &outBuf,const QCString &fileName)
1216 commentcnvYY_state extra(inBuf,outBuf);
1217 commentcnvYYlex_init_extra(&extra,&yyscanner);
1219 commentcnvYYset_debug(Debug::isFlagSet(Debug::Lex_commentcnv)?1:0,yyscanner);
1221 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1222 //printf("convertCppComments(%s)\n",fileName);
1223 yyextra->inBufPos = 0;
1225 yyextra->mlBrief = Config_getBool(MULTILINE_CPP_IS_BRIEF);
1226 yyextra->skip = FALSE;
1227 yyextra->fileName = fileName;
1228 yyextra->lang = getLanguageFromFileName(fileName);
1229 yyextra->pythonDocString = FALSE;
1230 yyextra->lineNr = 1;
1231 while (!yyextra->condStack.empty()) yyextra->condStack.pop();
1232 clearCommentStack(yyscanner);
1233 yyextra->vhdl = FALSE;
1235 DebugLex debugLex(Debug::Lex_commentcnv,__FILE__, qPrint(fileName));
1236 yyextra->isFixedForm = FALSE;
1237 if (yyextra->lang==SrcLangExt_Fortran)
1239 FortranFormat fmt = convertFileNameFortranParserCode(fileName);
1240 yyextra->isFixedForm = recognizeFixedForm(QCString(inBuf.data()),fmt);
1243 if (yyextra->lang==SrcLangExt_Markdown)
1245 yyextra->nestingCount=0;
1247 yyextra->commentStack.push(yyextra->lineNr);
1254 while (!yyextra->condStack.empty())
1256 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
1257 QCString sectionInfo(" ");
1258 if (ctx.sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",ctx.sectionId.stripWhiteSpace().data());
1259 warn(yyextra->fileName,ctx.lineNr,"Conditional section%sdoes not have "
1260 "a corresponding \\endcond command within this file.",sectionInfo.data());
1261 yyextra->condStack.pop();
1263 if (yyextra->nestingCount>0 && yyextra->lang!=SrcLangExt_Markdown && yyextra->lang!=SrcLangExt_Fortran)
1265 QCString tmp("(probable line reference: ");
1267 while (!yyextra->commentStack.empty())
1269 int lineNr = yyextra->commentStack.top();
1270 if (!first) tmp += ", ";
1271 tmp += QCString().setNum(lineNr);
1273 yyextra->commentStack.pop();
1276 warn(yyextra->fileName,yyextra->lineNr,"Reached end of file while still inside a (nested) comment. "
1277 "Nesting level %d %s",yyextra->nestingCount,tmp.data());
1279 yyextra->nestingCount = 0;
1280 if (Debug::isFlagSet(Debug::CommentCnv))
1282 yyextra->outBuf.at(yyextra->outBuf.curPos())='\0';
1283 Debug::print(Debug::CommentCnv,0,"-----------\nCommentCnv: %s\n"
1284 "output=[\n%s]\n-----------\n",qPrint(fileName),yyextra->outBuf.data()
1287 commentcnvYYlex_destroy(yyscanner);
1291 //----------------------------------------------------------------------------
1293 #if USE_STATE2STRING
1294 #include "commentcnv.l.h"