Doxygen
commentcnv.l
浏览该文件的文档.
1 /*****************************************************************************
2  *
3  *
4  *
5  * Copyright (C) 1997-2015 by Dimitri van Heesch.
6  *
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.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17 %option never-interactive
18 %option prefix="commentcnvYY"
19 %option reentrant
20 %option extra-type="struct commentcnvYY_state *"
21 %top{
22 #include <stdint.h>
23 // forward declare yyscan_t to improve type safety
24 #define YY_TYPEDEF_YY_SCANNER_T
25 struct yyguts_t;
26 typedef yyguts_t *yyscan_t;
27 }
28 
29 %{
30 
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stack>
35 #include <algorithm>
36 
37 #include "bufstr.h"
38 #include "debug.h"
39 #include "message.h"
40 #include "config.h"
41 #include "doxygen.h"
42 #include "util.h"
43 #include "condparser.h"
44 
45 #include <assert.h>
46 
47 #define YY_NO_INPUT 1
48 #define YY_NO_UNISTD_H 1
49 
50 #define ADDCHAR(c) yyextra->outBuf->addChar(c)
51 #define ADDARRAY(a,s) yyextra->outBuf->addArray(a,s)
52 
53 #define USE_STATE2STRING 0
54 
55 struct commentcnvYY_CondCtx
56 {
57  commentcnvYY_CondCtx(int line,QCString id,bool b)
58  : lineNr(line),sectionId(id), skip(b) {}
59  int lineNr;
60  QCString sectionId;
61  bool skip;
62 };
63 
64 struct CommentCtx
65 {
66  CommentCtx(int line)
67  : lineNr(line) {}
68  int lineNr;
69 };
70 
71 struct commentcnvYY_state
72 {
73  BufStr * inBuf = 0;
74  BufStr * outBuf = 0;
75  yy_size_t inBufPos = 0;
76  int col = 0;
77  int blockHeadCol = 0;
78  bool mlBrief = FALSE;
79  int readLineCtx = 0;
80  bool skip = FALSE;
81  QCString fileName;
82  int lineNr = 0;
83  int condCtx = 0;
84  std::stack<commentcnvYY_CondCtx> condStack;
85  std::stack<int> commentStack;
86  QCString blockName;
87  int lastCommentContext = 0;
88  bool inSpecialComment = FALSE;
89  bool inRoseComment= FALSE;
90  int stringContext = 0;
91  int charContext = 0;
92  int javaBlock = 0;
93  bool specialComment = FALSE;
94 
95  QCString aliasString;
96  int blockCount = 0;
97  bool lastEscaped = FALSE;
98  int lastBlockContext= 0;
99  bool pythonDocString = FALSE;
100  int nestingCount= 0;
101 
102  bool vhdl = FALSE; // for VHDL old style --! comment
103 
104  SrcLangExt lang = SrcLangExt_Unknown;
105  bool isFixedForm = FALSE; // For Fortran
106 };
107 
108 #if USE_STATE2STRING
109 static const char *stateToString(int state);
110 #endif
111 static inline int computeIndent(const char *s);
112 
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 &sectId);
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);
122 
123 
124 
125 
126 #undef YY_INPUT
127 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
128 
129 
130 %}
131 
132 MAILADR ("mailto:")?[a-z_A-Z0-9.+-]+"@"[a-z_A-Z0-9-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
133 
134 %option noyywrap
135 
136 %x Scan
137 %x SkipString
138 %x SkipChar
139 %x SComment
140 %x CComment
141 %x CNComment
142 %x Verbatim
143 %x VerbatimCode
144 %x ReadLine
145 %x CondLine
146 %x ReadAliasArgs
147 
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}
155 
156 FP_SUF [fFlL]
157 
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}
163 
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}?
169 
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 ---------------------------------------------------------------------------
175 
176  // C start comment
177 CCS "/\*"
178  // C end comment
179 CCE "*\/"
180  // Cpp comment
181 CPPC "/\/"
182 
183  // Optional any character
184 ANYopt .*
185 
186  // Optional white space
187 WSopt [ \t\r]*
188  // readline non special
189 RLopt [^\\@\n\*\/]*
190  // Optional slash
191 SLASHopt [/]*
192 
193 %%
194 
195 <Scan>{NUMBER} { //Note similar code in code.l
196  if (yyextra->lang!=SrcLangExt_Cpp) REJECT;
197  copyToOutput(yyscanner,yytext,(int)yyleng);
198  }
199 <Scan>[^"'!\/\n\\#,\-=; \t]* { /* eat anything that is not " / , or \n */
200  copyToOutput(yyscanner,yytext,(int)yyleng);
201  }
202 <Scan>[,= ;\t] { /* eat , so we have a nice separator in long initialization lines */
203  copyToOutput(yyscanner,yytext,(int)yyleng);
204  }
205 <Scan>"\"\"\""! { /* start of python long comment */
206  if (yyextra->lang!=SrcLangExt_Python)
207  {
208  REJECT;
209  }
210  else
211  {
212  yyextra->pythonDocString = TRUE;
213  yyextra->nestingCount=1;
214  clearCommentStack(yyscanner); /* to be on the save side */
215  copyToOutput(yyscanner,yytext,(int)yyleng);
216  BEGIN(CComment);
217  yyextra->commentStack.push(yyextra->lineNr);
218  }
219  }
220 <Scan>![><!]/.*\n {
221  if (yyextra->lang!=SrcLangExt_Fortran)
222  {
223  REJECT;
224  }
225  else
226  {
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 */
230  BEGIN(CComment);
231  yyextra->commentStack.push(yyextra->lineNr);
232  }
233  }
234 <Scan>[Cc\*][><!]/.*\n {
235  if (yyextra->lang!=SrcLangExt_Fortran)
236  {
237  REJECT;
238  }
239  else
240  {
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))
243  {
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 */
247  BEGIN(CComment);
248  yyextra->commentStack.push(yyextra->lineNr);
249  }
250  else
251  {
252  REJECT;
253  }
254  }
255  }
256 <Scan>!.*\n {
257  if (yyextra->lang!=SrcLangExt_Fortran)
258  {
259  REJECT;
260  }
261  else
262  {
263  copyToOutput(yyscanner,yytext,(int)yyleng);
264  }
265  }
266 <Scan>[Cc\*].*\n {
267  if (yyextra->lang!=SrcLangExt_Fortran)
268  {
269  REJECT;
270  }
271  else
272  {
273  if (yyextra->col == 0)
274  {
275  copyToOutput(yyscanner,yytext,(int)yyleng);
276  }
277  else
278  {
279  REJECT;
280  }
281  }
282  }
283 <Scan>"\"" { /* start of a string */
284  copyToOutput(yyscanner,yytext,(int)yyleng);
285  yyextra->stringContext = YY_START;
286  BEGIN(SkipString);
287  }
288 <Scan>' {
289  copyToOutput(yyscanner,yytext,(int)yyleng);
290  yyextra->charContext = YY_START;
291  if (yyextra->lang!=SrcLangExt_VHDL)
292  {
293  BEGIN(SkipChar);
294  }
295  }
296 <Scan>\n { /* new line */
297  copyToOutput(yyscanner,yytext,(int)yyleng);
298  }
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)
302  {
303  REJECT; // bail out if we do not need to convert
304  }
305  else
306  {
307  int i=3;
308  if (yytext[2]=='/')
309  {
310  while (i<(int)yyleng && yytext[i]=='/') i++;
311  }
312  yyextra->blockHeadCol=yyextra->col;
313  copyToOutput(yyscanner,"/**",3);
314  replaceAliases(yyscanner,QCString(yytext+i));
315  yyextra->inSpecialComment=TRUE;
316  //BEGIN(SComment);
317  yyextra->readLineCtx=SComment;
318  BEGIN(ReadLine);
319  }
320  }
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;
328  BEGIN(SComment);
329  }
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;
334  BEGIN(ReadLine);
335  }
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;
340  BEGIN(ReadLine);
341  }
342 <Scan>{CCS}{CCE} { /* avoid matching next rule for empty C comment, see bug 711723 */
343  copyToOutput(yyscanner,yytext,(int)yyleng);
344  }
345 <Scan>{CCS}[*!]? { /* start of a C comment */
346  if (yyextra->lang==SrcLangExt_Python)
347  {
348  REJECT;
349  }
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)
355  BEGIN(CComment);
356  else
357  BEGIN(CNComment);
358  yyextra->commentStack.push(yyextra->lineNr);
359  }
360 <Scan>"#"("#")? {
361  if (yyextra->lang!=SrcLangExt_Python)
362  {
363  REJECT;
364  }
365  else
366  {
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 */
370  BEGIN(CComment);
371  yyextra->commentStack.push(yyextra->lineNr);
372  }
373  }
374 <Scan>"--"[^!][^\n]* {
375  if (yyextra->lang!=SrcLangExt_VHDL)
376  {
377  REJECT;
378  }
379  else
380  {
381  copyToOutput(yyscanner,yytext,(int)yyleng);
382  }
383  }
384 <Scan>"--!" {
385  if (yyextra->lang!=SrcLangExt_VHDL)
386  {
387  REJECT;
388  }
389  else
390  {
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 */
395  BEGIN(CComment);
396  yyextra->commentStack.push(yyextra->lineNr);
397  }
398  }
399 <Scan>![><!] {
400  if (yyextra->lang!=SrcLangExt_Fortran)
401  {
402  REJECT;
403  }
404  else
405  {
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 */
409  BEGIN(CComment);
410  yyextra->commentStack.push(yyextra->lineNr);
411  }
412  }
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);
416  }
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];
422  BEGIN(VerbatimCode);
423  }
424 <CComment,ReadLine>^[ \t]*("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
425  if (!Config_getBool(MARKDOWN_SUPPORT))
426  {
427  REJECT;
428  }
429  copyToOutput(yyscanner,yytext,(int)yyleng);
430  yyextra->lastCommentContext = YY_START;
431  yyextra->javaBlock=0;
432  yyextra->blockName=QCString(yytext).stripWhiteSpace().left(3);
433  BEGIN(VerbatimCode);
434  }
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)
440  {
441  yyextra->blockName="uml";
442  }
443  else
444  {
445  yyextra->blockName=&yytext[1];
446  }
447  BEGIN(VerbatimCode);
448  }
449 <CComment,ReadLine>[\\@]("f$"|"f["|"f{"|"f(") {
450  copyToOutput(yyscanner,yytext,(int)yyleng);
451  yyextra->blockName=&yytext[1];
452  if (yyextra->blockName.at(1)=='[')
453  {
454  yyextra->blockName.at(1)=']';
455  }
456  else if (yyextra->blockName.at(1)=='{')
457  {
458  yyextra->blockName.at(1)='}';
459  }
460  else if (yyextra->blockName.at(1)=='(')
461  {
462  yyextra->blockName.at(1)=')';
463  }
464  yyextra->lastCommentContext = YY_START;
465  BEGIN(Verbatim);
466  }
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;
471  BEGIN(Verbatim);
472  }
473 <Scan>"\\\"" { /* escaped double quote */
474  copyToOutput(yyscanner,yytext,(int)yyleng);
475  }
476 <Scan>"\\\\" { /* escaped backslash */
477  copyToOutput(yyscanner,yytext,(int)yyleng);
478  }
479 <Scan>. { /* any other character */
480  copyToOutput(yyscanner,yytext,(int)yyleng);
481  }
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
485  {
486  BEGIN(yyextra->lastCommentContext);
487  }
488  else if (&yytext[4]==yyextra->blockName)
489  {
490  BEGIN(yyextra->lastCommentContext);
491  }
492  }
493 <VerbatimCode>"{" {
494  if (yyextra->javaBlock==0)
495  {
496  REJECT;
497  }
498  else
499  {
500  yyextra->javaBlock++;
501  copyToOutput(yyscanner,yytext,(int)yyleng);
502  }
503  }
504 <VerbatimCode>"}" {
505  if (yyextra->javaBlock==0)
506  {
507  REJECT;
508  }
509  else
510  {
511  yyextra->javaBlock--;
512  if (yyextra->javaBlock==0)
513  {
514  copyToOutput(yyscanner," @endcode ",10);
515  BEGIN(yyextra->lastCommentContext);
516  }
517  else
518  {
519  copyToOutput(yyscanner,yytext,(int)yyleng);
520  }
521  }
522  }
523 <VerbatimCode>("```"[`]*|"~~~"[~]*) { /* end of markdown code block */
524  copyToOutput(yyscanner,yytext,(int)yyleng);
525  if (yytext[0]==yyextra->blockName[0])
526  {
527  BEGIN(yyextra->lastCommentContext);
528  }
529  }
530 <VerbatimCode>[\\@]("enddot"|"endcode"|"endmsc"|"enduml") { /* end of verbatim block */
531  copyToOutput(yyscanner,yytext,(int)yyleng);
532  if (&yytext[4]==yyextra->blockName)
533  {
534  BEGIN(yyextra->lastCommentContext);
535  }
536  }
537 <VerbatimCode>^[ \t]*{CPPC}[\!\/]? { /* skip leading comments */
538  if (!yyextra->inSpecialComment)
539  {
540  copyToOutput(yyscanner,yytext,(int)yyleng);
541  }
542  else
543  {
544  int l=0;
545  while (yytext[l]==' ' || yytext[l]=='\t')
546  {
547  l++;
548  }
549  copyToOutput(yyscanner,yytext,l);
550  if (yyleng-l==3) // ends with //! or ///
551  {
552  copyToOutput(yyscanner," * ",3);
553  }
554  else // ends with //
555  {
556  copyToOutput(yyscanner,"//",2);
557  }
558  }
559  }
560 <Verbatim,VerbatimCode>[^`~@\/\\\n{}]* { /* any character not a backslash or new line or } */
561  copyToOutput(yyscanner,yytext,(int)yyleng);
562  }
563 <Verbatim,VerbatimCode>\n { /* new line in verbatim block */
564  copyToOutput(yyscanner,yytext,(int)yyleng);
565  }
566 <Verbatim>^[ \t]*{CPPC}[/!] {
567  if (yyextra->blockName=="dot" || yyextra->blockName=="msc" || yyextra->blockName=="uml" || yyextra->blockName.at(0)=='f')
568  {
569  // see bug 487871, strip /// from dot images and formulas.
570  int l=0;
571  while (yytext[l]==' ' || yytext[l]=='\t')
572  {
573  l++;
574  }
575  copyToOutput(yyscanner,yytext,l);
576  copyToOutput(yyscanner," ",3);
577  }
578  else // even slashes are verbatim (e.g. \verbatim, \code)
579  {
580  REJECT;
581  }
582  }
583 <Verbatim,VerbatimCode>. { /* any other character */
584  copyToOutput(yyscanner,yytext,(int)yyleng);
585  }
586 <SkipString>\\. { /* escaped character in string */
587  if (yyextra->lang==SrcLangExt_Fortran || yyextra->lang==SrcLangExt_VHDL)
588  {
589  unput(yytext[1]);
590  copyToOutput(yyscanner,yytext,1);
591  }
592  else
593  {
594  copyToOutput(yyscanner,yytext,(int)yyleng);
595  }
596  }
597 <SkipString>"\"" { /* end of string */
598  copyToOutput(yyscanner,yytext,(int)yyleng);
599  BEGIN(yyextra->stringContext);
600  }
601 <SkipString>. { /* any other string character */
602  copyToOutput(yyscanner,yytext,(int)yyleng);
603  }
604 <SkipString>\n { /* new line inside string (illegal for some compilers) */
605  copyToOutput(yyscanner,yytext,(int)yyleng);
606  }
607 <SkipChar>\\. { /* escaped character */
608  if (yyextra->lang==SrcLangExt_Fortran || yyextra->lang==SrcLangExt_VHDL)
609  {
610  unput(yytext[1]);
611  copyToOutput(yyscanner,yytext,1);
612  }
613  else
614  {
615  copyToOutput(yyscanner,yytext,(int)yyleng);
616  }
617  }
618 <SkipChar>' { /* end of character literal */
619  copyToOutput(yyscanner,yytext,(int)yyleng);
620  BEGIN(yyextra->charContext);
621  }
622 <SkipChar>. { /* any other string character */
623  copyToOutput(yyscanner,yytext,(int)yyleng);
624  }
625 <SkipChar>\n { /* new line character */
626  copyToOutput(yyscanner,yytext,(int)yyleng);
627  }
628 
629 <CComment,CNComment>[^ `~<\\!@*\n{\"\/]* { /* anything that is not a '*' or command */
630  copyToOutput(yyscanner,yytext,(int)yyleng);
631  }
632 <CComment,CNComment>"*"+[^*\/\\@\n{\"]* { /* stars without slashes */
633  copyToOutput(yyscanner,yytext,(int)yyleng);
634  }
635 <CComment>"\"\"\"" { /* end of Python docstring */
636  if (yyextra->lang!=SrcLangExt_Python)
637  {
638  REJECT;
639  }
640  else
641  {
642  yyextra->nestingCount--;
643  yyextra->pythonDocString = FALSE;
644  copyToOutput(yyscanner,yytext,(int)yyleng);
645  BEGIN(Scan);
646  }
647  }
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)
652  {
653  BEGIN(Scan);
654  }
655  }
656 <CComment,CNComment>"/"+"*" { /* nested C comment */
657  if (yyextra->lang==SrcLangExt_Python ||
658  yyextra->lang==SrcLangExt_Markdown)
659  {
660  REJECT;
661  }
662  yyextra->nestingCount++;
663  yyextra->commentStack.push(yyextra->lineNr);
664  copyToOutput(yyscanner,yytext,(int)yyleng);
665  }
666 <CComment,CNComment>"*"+"/" { /* end of C comment */
667  if (yyextra->lang==SrcLangExt_Python ||
668  yyextra->lang==SrcLangExt_Markdown)
669  {
670  REJECT;
671  }
672  else
673  {
674  copyToOutput(yyscanner,yytext,(int)yyleng);
675  yyextra->nestingCount--;
676  if (yyextra->nestingCount<=0)
677  {
678  BEGIN(Scan);
679  }
680  else
681  {
682  //yyextra->nestingCount--;
683  yyextra->commentStack.pop();
684  }
685  }
686  }
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)
690  {
691  REJECT;
692  }
693  else
694  {
695  if (yyextra->vhdl) // inside --! comment
696  {
697  yyextra->vhdl = FALSE;
698  copyToOutput(yyscanner,yytext,(int)yyleng);
699  BEGIN(Scan);
700  }
701  else // C-type comment
702  {
703  REJECT;
704  }
705  }
706  }
707 <CComment,CNComment>"\n"/[ \t]*"-" {
708  if (yyextra->lang!=SrcLangExt_Python || yyextra->pythonDocString)
709  {
710  REJECT;
711  }
712  else
713  {
714  copyToOutput(yyscanner,yytext,(int)yyleng);
715  BEGIN(Scan);
716  }
717  }
718 <CComment,CNComment>"\n"/[ \t]*[^ \t#\-] {
719  if (yyextra->lang==SrcLangExt_Python)
720  {
721  if (yyextra->pythonDocString)
722  {
723  REJECT;
724  }
725  else
726  {
727  copyToOutput(yyscanner,yytext,(int)yyleng);
728  BEGIN(Scan);
729  }
730  }
731  else if (yyextra->lang==SrcLangExt_VHDL)
732  {
733  if (yyextra->vhdl) // inside --! comment
734  {
735  yyextra->vhdl = FALSE;
736  copyToOutput(yyscanner,yytext,(int)yyleng);
737  BEGIN(Scan);
738  }
739  else // C-type comment
740  {
741  REJECT;
742  }
743  }
744  else
745  {
746  REJECT;
747  }
748  }
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);
753  BEGIN(SkipChar);
754  }
755 <CComment,CNComment>"\"" {
756  yyextra->stringContext = YY_START;
757  copyToOutput(yyscanner,yytext,(int)yyleng);
758  BEGIN(SkipString);
759  }
760  */
761 <CComment,CNComment>. {
762  copyToOutput(yyscanner,yytext,(int)yyleng);
763  }
764 <SComment>^[ \t]*{CPPC}"/"{SLASHopt}/\n {
765  replaceComment(yyscanner,0);
766  }
767 <SComment>\n[ \t]*{CPPC}"/"{SLASHopt}/\n {
768  replaceComment(yyscanner,1);
769  }
770 <SComment>^[ \t]*{CPPC}"/"[^\/\n]/.*\n {
771  replaceComment(yyscanner,0);
772  yyextra->readLineCtx=YY_START;
773  BEGIN(ReadLine);
774  }
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;
781  BEGIN(Scan);
782  }
783 <SComment>\n[ \t]*{CPPC}"/"[^\/\n]/.*\n {
784  replaceComment(yyscanner,1);
785  yyextra->readLineCtx=YY_START;
786  BEGIN(ReadLine);
787  }
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;
793  BEGIN(ReadLine);
794  }
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;
800  BEGIN(ReadLine);
801  }
802 <SComment>^[ \t]*{CPPC}"##"/.*\n {
803  if (!yyextra->inRoseComment)
804  {
805  REJECT;
806  }
807  else
808  {
809  replaceComment(yyscanner,0);
810  yyextra->readLineCtx=YY_START;
811  BEGIN(ReadLine);
812  }
813  }
814 <SComment>\n[ \t]*{CPPC}"##"/.*\n {
815  if (!yyextra->inRoseComment)
816  {
817  REJECT;
818  }
819  else
820  {
821  replaceComment(yyscanner,1);
822  yyextra->readLineCtx=YY_START;
823  BEGIN(ReadLine);
824  }
825  }
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;
831  BEGIN(Scan);
832  }
833 <ReadLine>{CCS}"*" {
834  copyToOutput(yyscanner,"/&zwj;**",8);
835  }
836 <ReadLine>{CCE} {
837  copyToOutput(yyscanner,"*&zwj;/",7);
838  }
839 <ReadLine>"*" {
840  copyToOutput(yyscanner,yytext,(int)yyleng);
841  }
842 <ReadLine>{RLopt} {
843  copyToOutput(yyscanner,yytext,(int)yyleng);
844  }
845 <ReadLine>{RLopt}/\n {
846  copyToOutput(yyscanner,yytext,(int)yyleng);
847  BEGIN(yyextra->readLineCtx);
848  }
849 <CComment,CNComment,ReadLine>[\\@][\\@][~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
850  copyToOutput(yyscanner,yytext,(int)yyleng);
851  }
852 <CComment,ReadLine>[\\@]"cond"/[^a-z_A-Z0-9] { // conditional section
853  yyextra->condCtx = YY_START;
854  BEGIN(CondLine);
855  }
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)
860  {
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)
866  {
867  ADDCHAR('/');
868  ADDCHAR('*');
869  if (yyextra->specialComment)
870  {
871  ADDCHAR('*');
872  }
873  }
874  }
875  }
876 <CondLine>[!()&| \ta-z_A-Z0-9.\-]+ {
877  handleCondSectionId(yyscanner,yytext);
878  }
879 <CComment,ReadLine>[\\@]"cond"{WSopt}/\n {
880  yyextra->condCtx=YY_START;
881  handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
882  }
883 <CondLine>. { // forgot section id?
884  handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
885  if (*yytext=='\n') yyextra->lineNr++;
886  }
887 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias without arguments
888  replaceAliases(yyscanner,QCString(yytext));
889  }
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 );
896  }
897 <ReadAliasArgs>^[ \t]*{CPPC}[/!]/[^\n]+ { // skip leading special comments (see bug 618079)
898  }
899 <ReadAliasArgs>{CCE} { // oops, end of comment in the middle of an alias?
900  if (yyextra->lang==SrcLangExt_Python)
901  {
902  REJECT;
903  }
904  else // abort the alias, restart scanning
905  {
906  copyToOutput(yyscanner,yyextra->aliasString.data(),yyextra->aliasString.length());
907  copyToOutput(yyscanner,yytext,(int)yyleng);
908  BEGIN(Scan);
909  }
910  }
911 <ReadAliasArgs>[^{}\n\\\*]+ {
912  yyextra->aliasString+=yytext;
913  yyextra->lastEscaped=FALSE;
914  }
915 <ReadAliasArgs>"\\" {
916  if (yyextra->lastEscaped) yyextra->lastEscaped=FALSE;
917  else yyextra->lastEscaped=TRUE;
918  yyextra->aliasString+=yytext;
919  }
920 <ReadAliasArgs>\n {
921  yyextra->aliasString+=yytext;
922  yyextra->lineNr++;
923  yyextra->lastEscaped=FALSE;
924  }
925 <ReadAliasArgs>"{" {
926  yyextra->aliasString+=yytext;
927  if (!yyextra->lastEscaped) yyextra->blockCount++;
928  yyextra->lastEscaped=FALSE;
929  }
930 <ReadAliasArgs>"}" {
931  yyextra->aliasString+=yytext;
932  if (!yyextra->lastEscaped) yyextra->blockCount--;
933  if (yyextra->blockCount==0)
934  {
935  replaceAliases(yyscanner,yyextra->aliasString);
936  BEGIN( yyextra->lastBlockContext );
937  }
938  yyextra->lastEscaped=FALSE;
939  }
940 <ReadAliasArgs>. {
941  yyextra->aliasString+=yytext;
942  yyextra->lastEscaped=FALSE;
943  }
944 <ReadLine>. {
945  copyToOutput(yyscanner,yytext,(int)yyleng);
946  }
947 
948 <*>. {
949  copyToOutput(yyscanner,yytext,(int)yyleng);
950  }
951 %%
952 
953 static void replaceCommentMarker(yyscan_t yyscanner,const char *s,int len)
954 {
955  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
956  const char *p=s;
957  char c;
958  // copy leading blanks
959  while ((c=*p) && (c==' ' || c=='\t' || c=='\n'))
960  {
961  ADDCHAR(c);
962  yyextra->lineNr += c=='\n';
963  p++;
964  }
965  // replace start of comment marker by blanks and the last character by a *
966  int blanks=0;
967  while ((c=*p) && (c=='/' || c=='!' || c=='#'))
968  {
969  blanks++;
970  p++;
971  if (*p=='<') // comment-after-item marker
972  {
973  blanks++;
974  p++;
975  }
976  if (c=='!') // end after first !
977  {
978  break;
979  }
980  }
981  if (blanks>0)
982  {
983  while (blanks>2)
984  {
985  ADDCHAR(' ');
986  blanks--;
987  }
988  if (blanks>1) ADDCHAR('*');
989  ADDCHAR(' ');
990  }
991  // copy comment line to output
992  ADDARRAY(p,len-(int)(p-s));
993 }
994 
995 static inline int computeIndent(const char *s)
996 {
997  int col=0;
998  static int tabSize=Config_getInt(TAB_SIZE);
999  const char *p=s;
1000  char c;
1001  while ((c=*p++))
1002  {
1003  if (c==' ') col++;
1004  else if (c=='\t') col+=tabSize-(col%tabSize);
1005  else break;
1006  }
1007  return col;
1008 }
1009 
1010 static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len)
1011 {
1012  int tabSize=Config_getInt(TAB_SIZE);
1013  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1014  int i;
1015  if (yyextra->skip) // only add newlines.
1016  {
1017  for (i=0;i<len;i++)
1018  {
1019  switch(s[i])
1020  {
1021  case '\n':
1022  ADDCHAR('\n');
1023  yyextra->lineNr++;
1024  yyextra->col=0;
1025  break;
1026  case '\t':
1027  yyextra->col+=tabSize-(yyextra->col%tabSize);
1028  break;
1029  default:
1030  yyextra->col++;
1031  break;
1032  }
1033  }
1034  }
1035  else if (len>0)
1036  {
1037  ADDARRAY(s,len);
1038  for (i=0;i<len;i++)
1039  {
1040  switch (s[i])
1041  {
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;
1047  }
1048  }
1049  }
1050 }
1051 
1052 static void clearCommentStack(yyscan_t yyscanner)
1053 {
1054  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1055  while (!yyextra->commentStack.empty()) yyextra->commentStack.pop();
1056 }
1057 
1058 static void startCondSection(yyscan_t yyscanner,const QCString &sectId)
1059 {
1060  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1061  //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1062  CondParser prs;
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
1066  {
1067  yyextra->skip=TRUE;
1068  }
1069 }
1070 
1071 static void endCondSection(yyscan_t yyscanner)
1072 {
1073  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1074  if (yyextra->condStack.empty())
1075  {
1076  warn(yyextra->fileName,yyextra->lineNr,"Found \\endcond command without matching \\cond");
1077  yyextra->skip=FALSE;
1078  }
1079  else
1080  {
1081  const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
1082  yyextra->skip=ctx.skip;
1083  yyextra->condStack.pop();
1084  }
1085  //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1086 }
1087 
1088 static void handleCondSectionId(yyscan_t yyscanner,const char *expression)
1089 {
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)
1095  {
1096  if (yyextra->lang!=SrcLangExt_Python &&
1097  yyextra->lang!=SrcLangExt_VHDL &&
1098  yyextra->lang!=SrcLangExt_Markdown &&
1099  yyextra->lang!=SrcLangExt_Fortran)
1100  {
1101  ADDCHAR('*');
1102  ADDCHAR('/');
1103  }
1104  }
1105  if (yyextra->readLineCtx==SComment)
1106  {
1107  BEGIN(SComment);
1108  }
1109  else
1110  {
1111  BEGIN(yyextra->condCtx);
1112  }
1113 }
1114 
1115 /** copies string \a s with length \a len to the output, while
1116  * replacing any alias commands found in the string.
1117  */
1118 static void replaceAliases(yyscan_t yyscanner,const QCString &s)
1119 {
1120  QCString result = resolveAliasCmd(s);
1121  //printf("replaceAliases(%s)->'%s'\n",s,result.data());
1122  copyToOutput(yyscanner,result.data(),result.length());
1123 }
1124 
1125 
1126 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
1127 {
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;
1133  return bytesToCopy;
1134 }
1135 
1136 static void replaceComment(yyscan_t yyscanner,int offset)
1137 {
1138  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1139  if (yyextra->mlBrief || yyextra->skip)
1140  {
1141  copyToOutput(yyscanner,yytext,(int)yyleng);
1142  }
1143  else
1144  {
1145  //printf("replaceComment(%s)\n",yytext);
1146  int i=computeIndent(&yytext[offset]);
1147  if (i==yyextra->blockHeadCol)
1148  {
1149  replaceCommentMarker(yyscanner,yytext,(int)yyleng);
1150  }
1151  else
1152  {
1153  copyToOutput(yyscanner," */",3);
1154  for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
1155  yyextra->inSpecialComment=FALSE;
1156  BEGIN(Scan);
1157  }
1158  }
1159 }
1160 
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)
1166  */
1167 void convertCppComments(BufStr *inBuf,BufStr *outBuf,const QCString &fileName)
1168 {
1169  yyscan_t yyscanner;
1170  commentcnvYY_state extra;
1171  commentcnvYYlex_init_extra(&extra,&yyscanner);
1172 #ifdef FLEX_DEBUG
1173  commentcnvYYset_debug(1,yyscanner);
1174 #endif
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;
1180  yyextra->col = 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;
1190 
1191  printlex(yy_flex_debug, TRUE, __FILE__, qPrint(fileName));
1192  yyextra->isFixedForm = FALSE;
1193  if (yyextra->lang==SrcLangExt_Fortran)
1194  {
1195  FortranFormat fmt = convertFileNameFortranParserCode(fileName);
1196  yyextra->isFixedForm = recognizeFixedForm(QCString(inBuf->data()),fmt);
1197  }
1198 
1199  if (yyextra->lang==SrcLangExt_Markdown)
1200  {
1201  yyextra->nestingCount=0;
1202  BEGIN(CComment);
1203  yyextra->commentStack.push(yyextra->lineNr);
1204  }
1205  else
1206  {
1207  BEGIN(Scan);
1208  }
1209  yylex(yyscanner);
1210  while (!yyextra->condStack.empty())
1211  {
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();
1218  }
1219  if (yyextra->nestingCount>0 && yyextra->lang!=SrcLangExt_Markdown && yyextra->lang!=SrcLangExt_Fortran)
1220  {
1221  QCString tmp("(probable line reference: ");
1222  bool first = TRUE;
1223  while (!yyextra->commentStack.empty())
1224  {
1225  int lineNr = yyextra->commentStack.top();
1226  if (!first) tmp += ", ";
1227  tmp += QCString().setNum(lineNr);
1228  first = FALSE;
1229  yyextra->commentStack.pop();
1230  }
1231  tmp += ")";
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());
1234  }
1235  yyextra->nestingCount = 0;
1236  if (Debug::isFlagSet(Debug::CommentCnv))
1237  {
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()
1241  );
1242  }
1243  printlex(yy_flex_debug, FALSE, __FILE__, qPrint(fileName));
1244  commentcnvYYlex_destroy(yyscanner);
1245 }
1246 
1247 
1248 //----------------------------------------------------------------------------
1249 
1250 #if USE_STATE2STRING
1251 #include "commentcnv.l.h"
1252 #endif