1 /*****************************************************************************
5 * Copyright (C) 1997-2013 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.
20 #define YY_NEVER_INTERACTIVE 1
28 #include <qtextstream.h>
37 #include "condparser.h"
43 #define ADDCHAR(c) g_outBuf->addChar(c)
44 #define ADDARRAY(a,s) g_outBuf->addArray(a,s)
48 CondCtx(int line,QCString id,bool b)
49 : lineNr(line),sectionId(id), skip(b) {}
55 static BufStr * g_inBuf;
56 static BufStr * g_outBuf;
57 static int g_inBufPos;
59 static int g_blockHeadCol;
60 static bool g_mlBrief;
61 static int g_readLineCtx;
63 static QCString g_fileName;
66 static QStack<CondCtx> g_condStack;
67 static QCString g_blockName;
68 static int g_lastCommentContext;
69 static bool g_inSpecialComment;
70 static bool g_inRoseComment;
71 static int g_stringContext;
72 static int g_charContext;
73 static int g_javaBlock;
74 static bool g_specialComment;
76 static QCString g_aliasString;
77 static int g_blockCount;
78 static bool g_lastEscaped;
79 static int g_lastBlockContext;
80 static bool g_pythonDocString;
81 static int g_nestingCount;
83 static SrcLangExt g_lang;
84 static bool isFixedForm; // For Fortran
86 static void replaceCommentMarker(const char *s,int len)
90 // copy leading blanks
91 while ((c=*p) && (c==' ' || c=='\t' || c=='\n'))
97 // replace start of comment marker by blanks and the last character by a *
99 while ((c=*p) && (c=='/' || c=='!' || c=='#'))
103 if (*p=='<') // comment-after-item marker
108 if (c=='!') // end after first !
120 if (blanks>1) ADDCHAR('*');
123 // copy comment line to output
124 ADDARRAY(p,len-(int)(p-s));
127 static inline int computeIndent(const char *s)
130 static int tabSize=Config_getInt("TAB_SIZE");
136 else if (c=='\t') col+=tabSize-(col%tabSize);
142 static inline void copyToOutput(const char *s,int len)
145 if (g_skip) // only add newlines.
152 //fprintf(stderr,"---> skip %d\n",g_lineNr);
160 static int tabSize=Config_getInt("TAB_SIZE");
166 //fprintf(stderr,"---> copy %d\n",g_lineNr);
168 case '\t': g_col+=tabSize-(g_col%tabSize); break;
169 default: g_col++; break;
175 static void startCondSection(const char *sectId)
177 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
179 bool expResult = prs.parse(g_fileName,g_lineNr,sectId);
180 g_condStack.push(new CondCtx(g_lineNr,sectId,g_skip));
181 if (!expResult) // not enabled
187 static void endCondSection()
189 if (g_condStack.isEmpty())
191 warn(g_fileName,g_lineNr,"Found \\endcond command without matching \\cond");
196 CondCtx *ctx = g_condStack.pop();
199 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
202 /** copies string \a s with length \a len to the output, while
203 * replacing any alias commands found in the string.
205 static void replaceAliases(const char *s)
207 QCString result = resolveAliasCmd(s);
208 //printf("replaceAliases(%s)->'%s'\n",s,result.data());
209 copyToOutput(result,result.length());
214 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
216 static int yyread(char *buf,int max_size)
218 int bytesInBuf = g_inBuf->curPos()-g_inBufPos;
219 int bytesToCopy = QMIN(max_size,bytesInBuf);
220 memcpy(buf,g_inBuf->data()+g_inBufPos,bytesToCopy);
221 g_inBufPos+=bytesToCopy;
225 void replaceComment(int offset);
244 <Scan>[^"'!\/\n\\#-,]* { /* eat anything that is not " / , or \n */
245 copyToOutput(yytext,(int)yyleng);
247 <Scan>[,] { /* eat , so we have a nice separator in long initialization lines */
248 copyToOutput(yytext,(int)yyleng);
250 <Scan>"\"\"\""! { /* start of python long comment */
251 if (g_lang!=SrcLangExt_Python)
257 g_pythonDocString = TRUE;
259 copyToOutput(yytext,(int)yyleng);
264 if (g_lang!=SrcLangExt_Fortran)
270 copyToOutput(yytext,(int)yyleng);
275 <Scan>[Cc\*][><!]/.*\n {
276 if (g_lang!=SrcLangExt_Fortran)
282 /* check for fixed format; we might have some conditional as part of multilene if like C<5 .and. & */
283 if (isFixedForm && (g_col == 0))
285 copyToOutput(yytext,(int)yyleng);
296 if (g_lang!=SrcLangExt_Fortran)
302 copyToOutput(yytext,(int)yyleng);
306 if (g_lang!=SrcLangExt_Fortran)
314 copyToOutput(yytext,(int)yyleng);
322 <Scan>"\"" { /* start of a string */
323 copyToOutput(yytext,(int)yyleng);
324 g_stringContext = YY_START;
328 copyToOutput(yytext,(int)yyleng);
329 g_charContext = YY_START;
330 if (g_lang!=SrcLangExt_VHDL)
335 <Scan>\n { /* new line */
336 copyToOutput(yytext,(int)yyleng);
338 <Scan>"//!"/.*\n[ \t]*"//"[\/!][^\/] | /* start C++ style special comment block */
339 <Scan>("///"[/]*)/[^/].*\n[ \t]*"//"[\/!][^\/] { /* start C++ style special comment block */
342 REJECT; // bail out if we do not need to convert
349 while (i<(int)yyleng && yytext[i]=='/') i++;
351 g_blockHeadCol=g_col;
352 copyToOutput("/**",3);
353 replaceAliases(yytext+i);
354 g_inSpecialComment=TRUE;
356 g_readLineCtx=SComment;
360 <Scan>"//##Documentation".*/\n { /* Start of Rational Rose ANSI C++ comment block */
361 if (g_mlBrief) REJECT;
362 int i=17; //=strlen("//##Documentation");
363 g_blockHeadCol=g_col;
364 copyToOutput("/**",3);
365 replaceAliases(yytext+i);
366 g_inRoseComment=TRUE;
369 <Scan>"//"/.*\n { /* one line C++ comment */
370 g_inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
371 copyToOutput(yytext,(int)yyleng);
372 g_readLineCtx=YY_START;
375 <Scan>"/**/" { /* avoid matching next rule for empty C comment, see bug 711723 */
376 copyToOutput(yytext,(int)yyleng);
378 <Scan>"/*"[*!]? { /* start of a C comment */
379 g_specialComment=(int)yyleng==3;
381 copyToOutput(yytext,(int)yyleng);
385 if (g_lang!=SrcLangExt_Python)
391 copyToOutput(yytext,(int)yyleng);
397 if (g_lang!=SrcLangExt_VHDL)
403 copyToOutput(yytext,(int)yyleng);
409 if (g_lang!=SrcLangExt_Fortran)
415 copyToOutput(yytext,(int)yyleng);
420 <CComment>"{@code"/[ \t\n] {
421 copyToOutput("@code",5);
422 g_lastCommentContext = YY_START;
424 g_blockName=&yytext[1];
427 <CComment,ReadLine>[\\@]("dot"|"code"|"msc")/[^a-z_A-Z0-9] { /* start of a verbatim block */
428 copyToOutput(yytext,(int)yyleng);
429 g_lastCommentContext = YY_START;
431 g_blockName=&yytext[1];
434 <CComment,ReadLine>[\\@]("f$"|"f["|"f{"[a-z]*) {
435 copyToOutput(yytext,(int)yyleng);
436 g_blockName=&yytext[1];
437 if (g_blockName.at(1)=='[')
439 g_blockName.at(1)=']';
441 else if (g_blockName.at(1)=='{')
443 g_blockName.at(1)='}';
445 g_lastCommentContext = YY_START;
448 <CComment,ReadLine>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly")/[^a-z_A-Z0-9] { /* start of a verbatim block */
449 copyToOutput(yytext,(int)yyleng);
450 g_blockName=&yytext[1];
451 g_lastCommentContext = YY_START;
454 <Scan>. { /* any ather character */
455 copyToOutput(yytext,(int)yyleng);
457 <Verbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"docbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}") { /* end of verbatim block */
458 copyToOutput(yytext,(int)yyleng);
459 if (yytext[1]=='f') // end of formula
461 BEGIN(g_lastCommentContext);
463 else if (&yytext[4]==g_blockName)
465 BEGIN(g_lastCommentContext);
476 copyToOutput(yytext,(int)yyleng);
489 copyToOutput(" @endcode ",10);
490 BEGIN(g_lastCommentContext);
494 copyToOutput(yytext,(int)yyleng);
498 <VerbatimCode>[\\@]("enddot"|"endcode"|"endmsc") { /* end of verbatim block */
499 copyToOutput(yytext,(int)yyleng);
500 if (&yytext[4]==g_blockName)
502 BEGIN(g_lastCommentContext);
505 <VerbatimCode>^[ \t]*"//"[\!\/]? { /* skip leading comments */
506 if (!g_inSpecialComment)
508 copyToOutput(yytext,(int)yyleng);
513 while (yytext[l]==' ' || yytext[l]=='\t')
517 copyToOutput(yytext,l);
518 if (yyleng-l==3) // ends with //! or ///
520 copyToOutput(" * ",3);
524 copyToOutput("//",2);
528 <Verbatim,VerbatimCode>[^@\/\\\n{}]* { /* any character not a backslash or new line or } */
529 copyToOutput(yytext,(int)yyleng);
531 <Verbatim,VerbatimCode>\n { /* new line in verbatim block */
532 copyToOutput(yytext,(int)yyleng);
534 <Verbatim>^[ \t]*"///" {
535 if (g_blockName=="dot" || g_blockName=="msc" || g_blockName.at(0)=='f')
537 // see bug 487871, strip /// from dot images and formulas.
539 while (yytext[l]==' ' || yytext[l]=='\t')
543 copyToOutput(yytext,l);
546 else // even slashes are verbatim (e.g. \verbatim, \code)
551 <Verbatim,VerbatimCode>. { /* any other character */
552 copyToOutput(yytext,(int)yyleng);
554 <SkipString>\\. { /* escaped character in string */
555 copyToOutput(yytext,(int)yyleng);
557 <SkipString>"\"" { /* end of string */
558 copyToOutput(yytext,(int)yyleng);
559 BEGIN(g_stringContext);
561 <SkipString>. { /* any other string character */
562 copyToOutput(yytext,(int)yyleng);
564 <SkipString>\n { /* new line inside string (illegal for some compilers) */
565 copyToOutput(yytext,(int)yyleng);
567 <SkipChar>\\. { /* escaped character */
568 copyToOutput(yytext,(int)yyleng);
570 <SkipChar>' { /* end of character literal */
571 copyToOutput(yytext,(int)yyleng);
572 BEGIN(g_charContext);
574 <SkipChar>. { /* any other string character */
575 copyToOutput(yytext,(int)yyleng);
577 <SkipChar>\n { /* new line character */
578 copyToOutput(yytext,(int)yyleng);
581 <CComment>[^\\!@*\n{\"\/]* { /* anything that is not a '*' or command */
582 copyToOutput(yytext,(int)yyleng);
584 <CComment>"*"+[^*/\\@\n{\"]* { /* stars without slashes */
585 copyToOutput(yytext,(int)yyleng);
587 <CComment>"\"\"\"" { /* end of Python docstring */
588 if (g_lang!=SrcLangExt_Python)
594 g_pythonDocString = FALSE;
595 copyToOutput(yytext,(int)yyleng);
599 <CComment>\n { /* new line in comment */
600 copyToOutput(yytext,(int)yyleng);
601 /* in case of Fortran always end of comment */
602 if (g_lang==SrcLangExt_Fortran)
607 <CComment>"/"+"*" { /* nested C comment */
609 copyToOutput(yytext,(int)yyleng);
611 <CComment>"*"+"/" { /* end of C comment */
612 if (g_lang==SrcLangExt_Python)
618 if (g_nestingCount<=0)
620 copyToOutput(yytext,(int)yyleng);
629 <CComment>"\n"/[ \t]*[^#] { /* end of Python comment */
630 if (g_lang!=SrcLangExt_Python || g_pythonDocString)
636 copyToOutput(yytext,(int)yyleng);
640 <CComment>"\n"/[ \t]*[^\-] { /* end of VHDL comment */
641 if (g_lang!=SrcLangExt_VHDL)
647 copyToOutput(yytext,(int)yyleng);
651 /* removed for bug 674842 (bug was introduced in rev 768)
653 g_charContext = YY_START;
654 copyToOutput(yytext,(int)yyleng);
658 g_stringContext = YY_START;
659 copyToOutput(yytext,(int)yyleng);
664 copyToOutput(yytext,(int)yyleng);
666 <SComment>^[ \t]*"///"[\/]*/\n {
669 <SComment>\n[ \t]*"///"[\/]*/\n {
672 <SComment>^[ \t]*"///"[^\/\n]/.*\n {
674 g_readLineCtx=YY_START;
677 <SComment>\n[ \t]*"///"[^\/\n]/.*\n {
679 g_readLineCtx=YY_START;
682 <SComment>^[ \t]*"//!" | // just //!
683 <SComment>^[ \t]*"//!<"/.*\n | // or //!< something
684 <SComment>^[ \t]*"//!"[^<]/.*\n { // or //!something
686 g_readLineCtx=YY_START;
689 <SComment>\n[ \t]*"//!" |
690 <SComment>\n[ \t]*"//!<"/.*\n |
691 <SComment>\n[ \t]*"//!"[^<\n]/.*\n {
693 g_readLineCtx=YY_START;
696 <SComment>^[ \t]*"//##"/.*\n {
697 if (!g_inRoseComment)
704 g_readLineCtx=YY_START;
708 <SComment>\n[ \t]*"//##"/.*\n {
709 if (!g_inRoseComment)
716 g_readLineCtx=YY_START;
720 <SComment>\n { /* end of special comment */
721 copyToOutput(" */",3);
722 copyToOutput(yytext,(int)yyleng);
723 g_inSpecialComment=FALSE;
724 g_inRoseComment=FALSE;
727 <ReadLine>[^\\@\n]*/\n {
728 copyToOutput(yytext,(int)yyleng);
729 BEGIN(g_readLineCtx);
731 <CComment,ReadLine>[\\@][\\@][~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
732 copyToOutput(yytext,(int)yyleng);
734 <CComment,ReadLine>[\\@]"cond"[ \t]+ { // conditional section
735 g_condCtx = YY_START;
738 <CComment,ReadLine>[\\@]"endcond"/[^a-z_A-Z0-9] { // end of conditional section
741 if (YY_START==CComment && oldSkip && !g_skip)
743 //printf("** Adding start of comment!\n");
744 if (g_lang!=SrcLangExt_Python &&
745 g_lang!=SrcLangExt_VHDL &&
746 g_lang!=SrcLangExt_Fortran)
750 if (g_specialComment)
757 <CondLine>[!()&| \ta-z_A-Z0-9.\-]+ {
759 startCondSection(yytext);
760 if ((g_condCtx==CComment || g_readLineCtx==SComment) &&
763 if (g_lang!=SrcLangExt_Python &&
764 g_lang!=SrcLangExt_VHDL &&
765 g_lang!=SrcLangExt_Fortran)
771 if (g_readLineCtx==SComment)
781 <CComment,ReadLine>[\\@]"cond"[ \t\r]*/\n |
782 <CondLine>. { // forgot section id?
783 if (YY_START!=CondLine) g_condCtx=YY_START;
785 startCondSection(" "); // fake section id causing the section to be hidden unconditionally
786 if ((g_condCtx==CComment || g_readLineCtx==SComment) &&
789 //printf("** Adding terminator for comment!\n");
790 if (g_lang!=SrcLangExt_Python &&
791 g_lang!=SrcLangExt_VHDL)
797 if (*yytext=='\n') g_lineNr++;
798 if (g_readLineCtx==SComment)
807 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias without arguments
808 replaceAliases(yytext);
810 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]*"{" { // expand alias with arguments
811 g_lastBlockContext=YY_START;
813 g_aliasString=yytext;
815 BEGIN( ReadAliasArgs );
817 <ReadAliasArgs>^[ \t]*"//"[/!]/[^\n]+ { // skip leading special comments (see bug 618079)
819 <ReadAliasArgs>"*/" { // oops, end of comment in the middle of an alias?
820 if (g_lang==SrcLangExt_Python)
824 else // abort the alias, restart scanning
826 copyToOutput(g_aliasString,g_aliasString.length());
827 copyToOutput(yytext,(int)yyleng);
831 <ReadAliasArgs>[^{}\n\\\*]+ {
832 g_aliasString+=yytext;
835 <ReadAliasArgs>"\\" {
836 if (g_lastEscaped) g_lastEscaped=FALSE;
837 else g_lastEscaped=TRUE;
838 g_aliasString+=yytext;
841 g_aliasString+=yytext;
846 g_aliasString+=yytext;
847 if (!g_lastEscaped) g_blockCount++;
851 g_aliasString+=yytext;
852 if (!g_lastEscaped) g_blockCount--;
855 replaceAliases(g_aliasString);
856 BEGIN( g_lastBlockContext );
861 g_aliasString+=yytext;
865 copyToOutput(yytext,(int)yyleng);
870 void replaceComment(int offset)
872 if (g_mlBrief || g_skip)
874 copyToOutput(yytext,(int)yyleng);
878 //printf("replaceComment(%s)\n",yytext);
879 int i=computeIndent(&yytext[offset]);
880 if (i==g_blockHeadCol)
882 replaceCommentMarker(yytext,(int)yyleng);
886 copyToOutput(" */",3);
887 int i;for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
888 g_inSpecialComment=FALSE;
894 // simplified way to know if this is fixed form
895 // duplicate in fortrancode.l
896 static bool recognizeFixedForm(const char* contents)
904 switch(contents[i]) {
916 if(column==1) return TRUE;
920 if(column>1 && column<7) return FALSE;
925 if(column==7) return TRUE;
933 /*! This function does three things:
934 * -# It converts multi-line C++ style comment blocks (that are aligned)
935 * to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
936 * -# It replaces aliases with their definition (see ALIASES)
937 * -# It handles conditional sections (cond...endcond blocks)
939 void convertCppComments(BufStr *inBuf,BufStr *outBuf,const char *fileName)
941 //printf("convertCppComments(%s)\n",fileName);
946 g_mlBrief = Config_getBool("MULTILINE_CPP_IS_BRIEF");
948 g_fileName = fileName;
949 g_lang = getLanguageFromFileName(fileName);
950 g_pythonDocString = FALSE;
953 g_condStack.setAutoDelete(TRUE);
955 printlex(yy_flex_debug, TRUE, __FILE__, fileName);
957 if (g_lang==SrcLangExt_Fortran)
959 isFixedForm = recognizeFixedForm(inBuf->data());
962 if (g_lang==SrcLangExt_Markdown)
972 while (!g_condStack.isEmpty())
974 CondCtx *ctx = g_condStack.pop();
975 QCString sectionInfo = " ";
976 if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label %s ",ctx->sectionId.data());
977 warn(g_fileName,ctx->lineNr,"Conditional section%sdoes not have "
978 "a corresponding \\endcond command within this file.",sectionInfo.data());
980 if (Debug::isFlagSet(Debug::CommentCnv))
982 g_outBuf->at(g_outBuf->curPos())='\0';
983 msg("-------------\n%s\n-------------\n",g_outBuf->data());
985 printlex(yy_flex_debug, FALSE, __FILE__, fileName);
989 //----------------------------------------------------------------------------
990 #if !defined(YY_FLEX_SUBMINOR_VERSION)
991 extern "C" { // some bogus code to keep the compiler happy
992 void commentcnvYYdummy() { yy_flex_realloc(0,0); }