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 {
commentcnvYY_CondCtxcommentcnvYY_CondCtx57 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 {
CommentCtxCommentCtx66 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 §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);
122
123
124
125
126 #undef YY_INPUT
127 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
128
129 // otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
getLexerFILE()130 static inline const char *getLexerFILE() {return __FILE__;}
131 #include "doxygen_lex.h"
132
133 %}
134
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\-]+
136
137 %option noyywrap
138
139 %x Scan
140 %x SkipString
141 %x SkipChar
142 %x SComment
143 %x CComment
144 %x CNComment
145 %x Verbatim
146 %x VerbatimCode
147 %x ReadLine
148 %x CondLine
149 %x ReadAliasArgs
150
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}
158
159 FP_SUF [fFlL]
160
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}
166
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}?
172
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 ---------------------------------------------------------------------------
178
179 // C start comment
180 CCS "/\*"
181 // C end comment
182 CCE "*\/"
183 // Cpp comment
184 CPPC "/\/"
185
186 // Optional any character
187 ANYopt .*
188
189 // Optional white space
190 WSopt [ \t\r]*
191 // readline non special
192 RLopt [^\\@\n\*\/]*
193 // Optional slash
194 SLASHopt [/]*
195
196 %%
197
198 <Scan>{NUMBER} { //Note similar code in code.l
199 if (yyextra->lang!=SrcLangExt_Cpp) REJECT;
200 copyToOutput(yyscanner,yytext,(int)yyleng);
201 }
202 <Scan>[^"'!\/\n\\#,\-=; \t]* { /* eat anything that is not " / , or \n */
203 copyToOutput(yyscanner,yytext,(int)yyleng);
204 }
205 <Scan>[,= ;\t] { /* eat , so we have a nice separator in long initialization lines */
206 copyToOutput(yyscanner,yytext,(int)yyleng);
207 }
208 <Scan>"\"\"\""! { /* start of python long comment */
209 if (yyextra->lang!=SrcLangExt_Python)
210 {
211 REJECT;
212 }
213 else
214 {
215 yyextra->pythonDocString = TRUE;
216 yyextra->nestingCount=1;
217 clearCommentStack(yyscanner); /* to be on the save side */
218 copyToOutput(yyscanner,yytext,(int)yyleng);
219 BEGIN(CComment);
220 yyextra->commentStack.push(yyextra->lineNr);
221 }
222 }
223 <Scan>![><!]/.*\n {
224 if (yyextra->lang!=SrcLangExt_Fortran)
225 {
226 REJECT;
227 }
228 else
229 {
230 copyToOutput(yyscanner,yytext,(int)yyleng);
231 yyextra->nestingCount=0; // Fortran doesn't have an end comment
232 clearCommentStack(yyscanner); /* to be on the save side */
233 BEGIN(CComment);
234 yyextra->commentStack.push(yyextra->lineNr);
235 }
236 }
237 <Scan>[Cc\*][><!]/.*\n {
238 if (yyextra->lang!=SrcLangExt_Fortran)
239 {
240 REJECT;
241 }
242 else
243 {
244 /* check for fixed format; we might have some conditional as part of multiline if like C<5 .and. & */
245 if (yyextra->isFixedForm && (yyextra->col == 0))
246 {
247 copyToOutput(yyscanner,yytext,(int)yyleng);
248 yyextra->nestingCount=0; // Fortran doesn't have an end comment
249 clearCommentStack(yyscanner); /* to be on the save side */
250 BEGIN(CComment);
251 yyextra->commentStack.push(yyextra->lineNr);
252 }
253 else
254 {
255 REJECT;
256 }
257 }
258 }
259 <Scan>!.*\n {
260 if (yyextra->lang!=SrcLangExt_Fortran)
261 {
262 REJECT;
263 }
264 else
265 {
266 copyToOutput(yyscanner,yytext,(int)yyleng);
267 }
268 }
269 <Scan>[Cc\*].*\n {
270 if (yyextra->lang!=SrcLangExt_Fortran)
271 {
272 REJECT;
273 }
274 else
275 {
276 if (yyextra->col == 0)
277 {
278 copyToOutput(yyscanner,yytext,(int)yyleng);
279 }
280 else
281 {
282 REJECT;
283 }
284 }
285 }
286 <Scan>"\"" { /* start of a string */
287 copyToOutput(yyscanner,yytext,(int)yyleng);
288 yyextra->stringContext = YY_START;
289 BEGIN(SkipString);
290 }
291 <Scan>' {
292 copyToOutput(yyscanner,yytext,(int)yyleng);
293 yyextra->charContext = YY_START;
294 if (yyextra->lang!=SrcLangExt_VHDL)
295 {
296 BEGIN(SkipChar);
297 }
298 }
299 <Scan>\n { /* new line */
300 copyToOutput(yyscanner,yytext,(int)yyleng);
301 }
302 <Scan>{CPPC}"!"/.*\n[ \t]*{CPPC}[\/!][^\/] | /* start C++ style special comment block */
303 <Scan>({CPPC}"/"[/]*)/[^/].*\n[ \t]*{CPPC}[\/!][^\/] { /* start C++ style special comment block */
304 if (yyextra->mlBrief)
305 {
306 REJECT; // bail out if we do not need to convert
307 }
308 else
309 {
310 int i=3;
311 if (yytext[2]=='/')
312 {
313 while (i<(int)yyleng && yytext[i]=='/') i++;
314 }
315 yyextra->blockHeadCol=yyextra->col;
316 copyToOutput(yyscanner,"/**",3);
317 replaceAliases(yyscanner,QCString(yytext+i));
318 yyextra->inSpecialComment=TRUE;
319 //BEGIN(SComment);
320 yyextra->readLineCtx=SComment;
321 BEGIN(ReadLine);
322 }
323 }
324 <Scan>{CPPC}"##Documentation"{ANYopt}/\n { /* Start of Rational Rose ANSI C++ comment block */
325 if (yyextra->mlBrief) REJECT;
326 int i=17; //=strlen("//##Documentation");
327 yyextra->blockHeadCol=yyextra->col;
328 copyToOutput(yyscanner,"/**",3);
329 replaceAliases(yyscanner,QCString(yytext+i));
330 yyextra->inRoseComment=TRUE;
331 BEGIN(SComment);
332 }
333 <Scan>{CPPC}[!\/]/.*\n[ \t]*{CPPC}[|\/][ \t]*[@\\]"}" { // next line contains an end marker, see bug 752712
334 yyextra->inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
335 copyToOutput(yyscanner,yytext,(int)yyleng);
336 yyextra->readLineCtx=YY_START;
337 BEGIN(ReadLine);
338 }
339 <Scan>{CPPC}/.*\n { /* one line C++ comment */
340 yyextra->inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
341 copyToOutput(yyscanner,yytext,(int)yyleng);
342 yyextra->readLineCtx=YY_START;
343 BEGIN(ReadLine);
344 }
345 <Scan>{CCS}{CCE} { /* avoid matching next rule for empty C comment, see bug 711723 */
346 copyToOutput(yyscanner,yytext,(int)yyleng);
347 }
348 <Scan>{CCS}[*!]? { /* start of a C comment */
349 if (yyextra->lang==SrcLangExt_Python)
350 {
351 REJECT;
352 }
353 yyextra->specialComment=(int)yyleng==3;
354 yyextra->nestingCount=1;
355 clearCommentStack(yyscanner); /* to be on the save side */
356 copyToOutput(yyscanner,yytext,(int)yyleng);
357 if (yyextra->specialComment)
358 BEGIN(CComment);
359 else
360 BEGIN(CNComment);
361 yyextra->commentStack.push(yyextra->lineNr);
362 }
363 <Scan>"#"("#")? {
364 if (yyextra->lang!=SrcLangExt_Python)
365 {
366 REJECT;
367 }
368 else
369 {
370 copyToOutput(yyscanner,yytext,(int)yyleng);
371 yyextra->nestingCount=0; // Python doesn't have an end comment for #
372 clearCommentStack(yyscanner); /* to be on the save side */
373 BEGIN(CComment);
374 yyextra->commentStack.push(yyextra->lineNr);
375 }
376 }
377 <Scan>"--"[^!][^\n]* {
378 if (yyextra->lang!=SrcLangExt_VHDL)
379 {
380 REJECT;
381 }
382 else
383 {
384 copyToOutput(yyscanner,yytext,(int)yyleng);
385 }
386 }
387 <Scan>"--!" {
388 if (yyextra->lang!=SrcLangExt_VHDL)
389 {
390 REJECT;
391 }
392 else
393 {
394 yyextra->vhdl = TRUE;
395 copyToOutput(yyscanner,yytext,(int)yyleng);
396 yyextra->nestingCount=0; // VHDL doesn't have an end comment
397 clearCommentStack(yyscanner); /* to be on the save side */
398 BEGIN(CComment);
399 yyextra->commentStack.push(yyextra->lineNr);
400 }
401 }
402 <Scan>![><!] {
403 if (yyextra->lang!=SrcLangExt_Fortran)
404 {
405 REJECT;
406 }
407 else
408 {
409 copyToOutput(yyscanner,yytext,(int)yyleng);
410 yyextra->nestingCount=0; // Fortran doesn't have an end comment
411 clearCommentStack(yyscanner); /* to be on the save side */
412 BEGIN(CComment);
413 yyextra->commentStack.push(yyextra->lineNr);
414 }
415 }
416 <CComment,CNComment,ReadLine>{MAILADDR} |
417 <CComment,CNComment,ReadLine>"<"{MAILADDR}">" { // Mail address, to prevent seeing e.g x@code-factory.org as start of a code block
418 copyToOutput(yyscanner,yytext,(int)yyleng);
419 }
420 <CComment>"{"[ \t]*"@code"/[ \t\n] {
421 copyToOutput(yyscanner,"@iliteral{code}",15);
422 yyextra->lastCommentContext = YY_START;
423 yyextra->javaBlock=1;
424 yyextra->blockName=&yytext[1];
425 BEGIN(VerbatimCode);
426 }
427 <CComment>"{"[ \t]*"@literal"/[ \t\n] {
428 copyToOutput(yyscanner,"@iliteral",9);
429 yyextra->lastCommentContext = YY_START;
430 yyextra->javaBlock=1;
431 yyextra->blockName=&yytext[1];
432 BEGIN(VerbatimCode);
433 }
434 <CComment,ReadLine>^[ \t]*("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
435 if (!Config_getBool(MARKDOWN_SUPPORT))
436 {
437 REJECT;
438 }
439 copyToOutput(yyscanner,yytext,(int)yyleng);
440 yyextra->lastCommentContext = YY_START;
441 yyextra->javaBlock=0;
442 yyextra->blockName=QCString(yytext).stripWhiteSpace().left(3);
443 BEGIN(VerbatimCode);
444 }
445 <CComment,ReadLine>[\\@]("dot"|"code"|"msc"|"startuml")/[^a-z_A-Z0-9] { /* start of a verbatim block */
446 copyToOutput(yyscanner,yytext,(int)yyleng);
447 yyextra->lastCommentContext = YY_START;
448 yyextra->javaBlock=0;
449 if (qstrcmp(&yytext[1],"startuml")==0)
450 {
451 yyextra->blockName="uml";
452 }
453 else
454 {
455 yyextra->blockName=&yytext[1];
456 }
457 BEGIN(VerbatimCode);
458 }
459 <CComment,ReadLine>[\\@]("f$"|"f["|"f{"|"f(") {
460 copyToOutput(yyscanner,yytext,(int)yyleng);
461 yyextra->blockName=&yytext[1];
462 if (yyextra->blockName.at(1)=='[')
463 {
464 yyextra->blockName.at(1)=']';
465 }
466 else if (yyextra->blockName.at(1)=='{')
467 {
468 yyextra->blockName.at(1)='}';
469 }
470 else if (yyextra->blockName.at(1)=='(')
471 {
472 yyextra->blockName.at(1)=')';
473 }
474 yyextra->lastCommentContext = YY_START;
475 BEGIN(Verbatim);
476 }
477 <CComment,ReadLine>[\\@]("verbatim"|"iliteral"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly")/[^a-z_A-Z0-9] { /* start of a verbatim block */
478 copyToOutput(yyscanner,yytext,(int)yyleng);
479 yyextra->blockName=&yytext[1];
480 yyextra->lastCommentContext = YY_START;
481 BEGIN(Verbatim);
482 }
483 <Scan>"\\\"" { /* escaped double quote */
484 copyToOutput(yyscanner,yytext,(int)yyleng);
485 }
486 <Scan>"\\\\" { /* escaped backslash */
487 copyToOutput(yyscanner,yytext,(int)yyleng);
488 }
489 <Scan>. { /* any other character */
490 copyToOutput(yyscanner,yytext,(int)yyleng);
491 }
492 <Verbatim>[\\@]("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}"|"f)") { /* end of verbatim block */
493 copyToOutput(yyscanner,yytext,(int)yyleng);
494 if (&yytext[1]==yyextra->blockName) // end of formula
495 {
496 BEGIN(yyextra->lastCommentContext);
497 }
498 else if (&yytext[4]==yyextra->blockName)
499 {
500 BEGIN(yyextra->lastCommentContext);
501 }
502 }
503 <VerbatimCode>"{" {
504 if (yyextra->javaBlock==0)
505 {
506 REJECT;
507 }
508 else
509 {
510 yyextra->javaBlock++;
511 copyToOutput(yyscanner,yytext,(int)yyleng);
512 }
513 }
514 <VerbatimCode>"}" {
515 if (yyextra->javaBlock==0)
516 {
517 REJECT;
518 }
519 else
520 {
521 yyextra->javaBlock--;
522 if (yyextra->javaBlock==0)
523 {
524 copyToOutput(yyscanner," @endiliteral ",14);
525 BEGIN(yyextra->lastCommentContext);
526 }
527 else
528 {
529 copyToOutput(yyscanner,yytext,(int)yyleng);
530 }
531 }
532 }
533 <VerbatimCode>("```"[`]*|"~~~"[~]*) { /* end of markdown code block */
534 copyToOutput(yyscanner,yytext,(int)yyleng);
535 if (yytext[0]==yyextra->blockName[0])
536 {
537 BEGIN(yyextra->lastCommentContext);
538 }
539 }
540 <VerbatimCode>[\\@]("enddot"|"endcode"|"endmsc"|"enduml") { /* end of verbatim block */
541 copyToOutput(yyscanner,yytext,(int)yyleng);
542 if (&yytext[4]==yyextra->blockName)
543 {
544 BEGIN(yyextra->lastCommentContext);
545 }
546 }
547 <VerbatimCode>^[ \t]*{CPPC}[\!\/]? { /* skip leading comments */
548 if (!yyextra->inSpecialComment)
549 {
550 copyToOutput(yyscanner,yytext,(int)yyleng);
551 }
552 else
553 {
554 int l=0;
555 while (yytext[l]==' ' || yytext[l]=='\t')
556 {
557 l++;
558 }
559 copyToOutput(yyscanner,yytext,l);
560 if (yyleng-l==3) // ends with //! or ///
561 {
562 copyToOutput(yyscanner," * ",3);
563 }
564 else // ends with //
565 {
566 copyToOutput(yyscanner,"//",2);
567 }
568 }
569 }
570 <Verbatim,VerbatimCode>[^`~@\/\\\n{}]* { /* any character not a backslash or new line or } */
571 copyToOutput(yyscanner,yytext,(int)yyleng);
572 }
573 <Verbatim,VerbatimCode>\n { /* new line in verbatim block */
574 copyToOutput(yyscanner,yytext,(int)yyleng);
575 }
576 <Verbatim>^[ \t]*{CPPC}[/!] {
577 if (yyextra->blockName=="dot" || yyextra->blockName=="msc" || yyextra->blockName=="uml" || yyextra->blockName.at(0)=='f')
578 {
579 // see bug 487871, strip /// from dot images and formulas.
580 int l=0;
581 while (yytext[l]==' ' || yytext[l]=='\t')
582 {
583 l++;
584 }
585 copyToOutput(yyscanner,yytext,l);
586 copyToOutput(yyscanner," ",3);
587 }
588 else // even slashes are verbatim (e.g. \verbatim, \code)
589 {
590 REJECT;
591 }
592 }
593 <Verbatim,VerbatimCode>. { /* any other character */
594 copyToOutput(yyscanner,yytext,(int)yyleng);
595 }
596 <SkipString>\\. { /* escaped character in string */
597 if (yyextra->lang==SrcLangExt_Fortran || yyextra->lang==SrcLangExt_VHDL)
598 {
599 unput(yytext[1]);
600 copyToOutput(yyscanner,yytext,1);
601 }
602 else
603 {
604 copyToOutput(yyscanner,yytext,(int)yyleng);
605 }
606 }
607 <SkipString>"\"" { /* end of string */
608 copyToOutput(yyscanner,yytext,(int)yyleng);
609 BEGIN(yyextra->stringContext);
610 }
611 <SkipString>. { /* any other string character */
612 copyToOutput(yyscanner,yytext,(int)yyleng);
613 }
614 <SkipString>\n { /* new line inside string (illegal for some compilers) */
615 copyToOutput(yyscanner,yytext,(int)yyleng);
616 }
617 <SkipChar>\\. { /* escaped character */
618 if (yyextra->lang==SrcLangExt_Fortran || yyextra->lang==SrcLangExt_VHDL)
619 {
620 unput(yytext[1]);
621 copyToOutput(yyscanner,yytext,1);
622 }
623 else
624 {
625 copyToOutput(yyscanner,yytext,(int)yyleng);
626 }
627 }
628 <SkipChar>' { /* end of character literal */
629 copyToOutput(yyscanner,yytext,(int)yyleng);
630 BEGIN(yyextra->charContext);
631 }
632 <SkipChar>. { /* any other string character */
633 copyToOutput(yyscanner,yytext,(int)yyleng);
634 }
635 <SkipChar>\n { /* new line character */
636 copyToOutput(yyscanner,yytext,(int)yyleng);
637 }
638
639 <CComment,CNComment>[^ `~<\\!@*\n{\"\/]* { /* anything that is not a '*' or command */
640 copyToOutput(yyscanner,yytext,(int)yyleng);
641 }
642 <CComment,CNComment>"*"+[^*\/\\@\n{\"]* { /* stars without slashes */
643 copyToOutput(yyscanner,yytext,(int)yyleng);
644 }
645 <CComment>"\"\"\"" { /* end of Python docstring */
646 if (yyextra->lang!=SrcLangExt_Python)
647 {
648 REJECT;
649 }
650 else
651 {
652 yyextra->nestingCount--;
653 yyextra->pythonDocString = FALSE;
654 copyToOutput(yyscanner,yytext,(int)yyleng);
655 BEGIN(Scan);
656 }
657 }
658 <CComment,CNComment>\n { /* new line in comment */
659 copyToOutput(yyscanner,yytext,(int)yyleng);
660 /* in case of Fortran always end of comment */
661 if (yyextra->lang==SrcLangExt_Fortran)
662 {
663 BEGIN(Scan);
664 }
665 }
666 <CComment,CNComment>"/"+"*" { /* nested C comment */
667 if (yyextra->lang==SrcLangExt_Python ||
668 yyextra->lang==SrcLangExt_Markdown)
669 {
670 REJECT;
671 }
672 yyextra->nestingCount++;
673 yyextra->commentStack.push(yyextra->lineNr);
674 copyToOutput(yyscanner,yytext,(int)yyleng);
675 }
676 <CComment,CNComment>"*"+"/" { /* end of C comment */
677 if (yyextra->lang==SrcLangExt_Python ||
678 yyextra->lang==SrcLangExt_Markdown)
679 {
680 REJECT;
681 }
682 else
683 {
684 copyToOutput(yyscanner,yytext,(int)yyleng);
685 yyextra->nestingCount--;
686 if (yyextra->nestingCount<=0)
687 {
688 BEGIN(Scan);
689 }
690 else
691 {
692 //yyextra->nestingCount--;
693 yyextra->commentStack.pop();
694 }
695 }
696 }
697 /* Python an VHDL share CComment,CNComment, so special attention for ending comments is required */
698 <CComment,CNComment>"\n"/[ \t]*"#" {
699 if (yyextra->lang!=SrcLangExt_VHDL)
700 {
701 REJECT;
702 }
703 else
704 {
705 if (yyextra->vhdl) // inside --! comment
706 {
707 yyextra->vhdl = FALSE;
708 copyToOutput(yyscanner,yytext,(int)yyleng);
709 BEGIN(Scan);
710 }
711 else // C-type comment
712 {
713 REJECT;
714 }
715 }
716 }
717 <CComment,CNComment>"\n"/[ \t]*"-" {
718 if (yyextra->lang!=SrcLangExt_Python || yyextra->pythonDocString)
719 {
720 REJECT;
721 }
722 else
723 {
724 copyToOutput(yyscanner,yytext,(int)yyleng);
725 BEGIN(Scan);
726 }
727 }
728 <CComment,CNComment>"\n"/[ \t]*[^ \t#\-] {
729 if (yyextra->lang==SrcLangExt_Python)
730 {
731 if (yyextra->pythonDocString)
732 {
733 REJECT;
734 }
735 else
736 {
737 copyToOutput(yyscanner,yytext,(int)yyleng);
738 BEGIN(Scan);
739 }
740 }
741 else if (yyextra->lang==SrcLangExt_VHDL)
742 {
743 if (yyextra->vhdl) // inside --! comment
744 {
745 yyextra->vhdl = FALSE;
746 copyToOutput(yyscanner,yytext,(int)yyleng);
747 BEGIN(Scan);
748 }
749 else // C-type comment
750 {
751 REJECT;
752 }
753 }
754 else
755 {
756 REJECT;
757 }
758 }
759 /* removed for bug 674842 (bug was introduced in rev 768)
760 <CComment,CNComment>"'" {
761 yyextra->charContext = YY_START;
762 copyToOutput(yyscanner,yytext,(int)yyleng);
763 BEGIN(SkipChar);
764 }
765 <CComment,CNComment>"\"" {
766 yyextra->stringContext = YY_START;
767 copyToOutput(yyscanner,yytext,(int)yyleng);
768 BEGIN(SkipString);
769 }
770 */
771 <CComment,CNComment>. {
772 copyToOutput(yyscanner,yytext,(int)yyleng);
773 }
774 <SComment>^[ \t]*{CPPC}"/"{SLASHopt}/\n {
775 replaceComment(yyscanner,0);
776 }
777 <SComment>\n[ \t]*{CPPC}"/"{SLASHopt}/\n {
778 replaceComment(yyscanner,1);
779 }
780 <SComment>^[ \t]*{CPPC}"/"[^\/\n]/.*\n {
781 replaceComment(yyscanner,0);
782 yyextra->readLineCtx=YY_START;
783 BEGIN(ReadLine);
784 }
785 <SComment>\n[ \t]*{CPPC}[\/!]("<")?[ \t]*[\\@]"}".*\n {
786 /* See Bug 752712: end the multiline comment when finding a @} or \} command */
787 copyToOutput(yyscanner," */",3);
788 copyToOutput(yyscanner,yytext,(int)yyleng);
789 yyextra->inSpecialComment=FALSE;
790 yyextra->inRoseComment=FALSE;
791 BEGIN(Scan);
792 }
793 <SComment>\n[ \t]*{CPPC}"/"[^\/\n]/.*\n {
794 replaceComment(yyscanner,1);
795 yyextra->readLineCtx=YY_START;
796 BEGIN(ReadLine);
797 }
798 <SComment>^[ \t]*{CPPC}"!" | // just //!
799 <SComment>^[ \t]*{CPPC}"!<"/.*\n | // or //!< something
800 <SComment>^[ \t]*{CPPC}"!"[^<]/.*\n { // or //!something
801 replaceComment(yyscanner,0);
802 yyextra->readLineCtx=YY_START;
803 BEGIN(ReadLine);
804 }
805 <SComment>\n[ \t]*{CPPC}"!" |
806 <SComment>\n[ \t]*{CPPC}"!<"/.*\n |
807 <SComment>\n[ \t]*{CPPC}"!"[^<\n]/.*\n {
808 replaceComment(yyscanner,1);
809 yyextra->readLineCtx=YY_START;
810 BEGIN(ReadLine);
811 }
812 <SComment>^[ \t]*{CPPC}"##"/.*\n {
813 if (!yyextra->inRoseComment)
814 {
815 REJECT;
816 }
817 else
818 {
819 replaceComment(yyscanner,0);
820 yyextra->readLineCtx=YY_START;
821 BEGIN(ReadLine);
822 }
823 }
824 <SComment>\n[ \t]*{CPPC}"##"/.*\n {
825 if (!yyextra->inRoseComment)
826 {
827 REJECT;
828 }
829 else
830 {
831 replaceComment(yyscanner,1);
832 yyextra->readLineCtx=YY_START;
833 BEGIN(ReadLine);
834 }
835 }
836 <SComment>\n { /* end of special comment */
837 copyToOutput(yyscanner," */",3);
838 copyToOutput(yyscanner,yytext,(int)yyleng);
839 yyextra->inSpecialComment=FALSE;
840 yyextra->inRoseComment=FALSE;
841 BEGIN(Scan);
842 }
843 <ReadLine>{CCS}"*" {
844 copyToOutput(yyscanner,"/‍**",8);
845 }
846 <ReadLine>{CCE} {
847 copyToOutput(yyscanner,"*‍/",7);
848 }
849 <ReadLine>"*" {
850 copyToOutput(yyscanner,yytext,(int)yyleng);
851 }
852 <ReadLine>{RLopt} {
853 copyToOutput(yyscanner,yytext,(int)yyleng);
854 }
855 <ReadLine>{RLopt}/\n {
856 copyToOutput(yyscanner,yytext,(int)yyleng);
857 BEGIN(yyextra->readLineCtx);
858 }
859 <CComment,CNComment,ReadLine>[\\@][\\@][~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
860 copyToOutput(yyscanner,yytext,(int)yyleng);
861 }
862 <CComment,ReadLine>[\\@]"cond"/[^a-z_A-Z0-9] { // conditional section
863 yyextra->condCtx = YY_START;
864 BEGIN(CondLine);
865 }
866 <CComment,ReadLine>[\\@]"endcond"/[^a-z_A-Z0-9] { // end of conditional section
867 bool oldSkip=yyextra->skip;
868 endCondSection(yyscanner);
869 if (YY_START==CComment && oldSkip && !yyextra->skip)
870 {
871 //printf("** Adding start of comment!\n");
872 if (yyextra->lang!=SrcLangExt_Python &&
873 yyextra->lang!=SrcLangExt_VHDL &&
874 yyextra->lang!=SrcLangExt_Markdown &&
875 yyextra->lang!=SrcLangExt_Fortran)
876 {
877 ADDCHAR('/');
878 ADDCHAR('*');
879 if (yyextra->specialComment)
880 {
881 ADDCHAR('*');
882 }
883 }
884 }
885 }
886 <CondLine>[!()&| \ta-z_A-Z0-9.\-]+ {
887 handleCondSectionId(yyscanner,yytext);
888 }
889 <CComment,ReadLine>[\\@]"cond"{WSopt}/\n {
890 yyextra->condCtx=YY_START;
891 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
892 }
893 <CondLine>\n |
894 <CondLine>. { // forgot section id?
895 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
896 if (*yytext=='\n') { yyextra->lineNr++; copyToOutput(yyscanner,"\n",1);}
897 }
898 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias without arguments
899 replaceAliases(yyscanner,QCString(yytext));
900 }
901 <CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]*"{" { // expand alias with arguments
902 yyextra->lastBlockContext=YY_START;
903 yyextra->blockCount=1;
904 yyextra->aliasString=yytext;
905 yyextra->lastEscaped=0;
906 BEGIN( ReadAliasArgs );
907 }
908 <ReadAliasArgs>^[ \t]*{CPPC}[/!]/[^\n]+ { // skip leading special comments (see bug 618079)
909 }
910 <ReadAliasArgs>{CCE} { // oops, end of comment in the middle of an alias?
911 if (yyextra->lang==SrcLangExt_Python)
912 {
913 REJECT;
914 }
915 else // abort the alias, restart scanning
916 {
917 copyToOutput(yyscanner,yyextra->aliasString.data(),yyextra->aliasString.length());
918 copyToOutput(yyscanner,yytext,(int)yyleng);
919 BEGIN(Scan);
920 }
921 }
922 <ReadAliasArgs>[^{}\n\\\*]+ {
923 yyextra->aliasString+=yytext;
924 yyextra->lastEscaped=FALSE;
925 }
926 <ReadAliasArgs>"\\" {
927 if (yyextra->lastEscaped) yyextra->lastEscaped=FALSE;
928 else yyextra->lastEscaped=TRUE;
929 yyextra->aliasString+=yytext;
930 }
931 <ReadAliasArgs>\n {
932 yyextra->aliasString+=yytext;
933 yyextra->lineNr++;
934 yyextra->lastEscaped=FALSE;
935 }
936 <ReadAliasArgs>"{" {
937 yyextra->aliasString+=yytext;
938 if (!yyextra->lastEscaped) yyextra->blockCount++;
939 yyextra->lastEscaped=FALSE;
940 }
941 <ReadAliasArgs>"}" {
942 yyextra->aliasString+=yytext;
943 if (!yyextra->lastEscaped) yyextra->blockCount--;
944 if (yyextra->blockCount==0)
945 {
946 replaceAliases(yyscanner,yyextra->aliasString);
947 BEGIN( yyextra->lastBlockContext );
948 }
949 yyextra->lastEscaped=FALSE;
950 }
951 <ReadAliasArgs>. {
952 yyextra->aliasString+=yytext;
953 yyextra->lastEscaped=FALSE;
954 }
955 <ReadLine>. {
956 copyToOutput(yyscanner,yytext,(int)yyleng);
957 }
958
959 <*>. {
960 copyToOutput(yyscanner,yytext,(int)yyleng);
961 }
962 /*
963 <*>\n { fprintf(stderr,"Lex scanner %s (%s) default rule newline for state %s.\n", __FILE__, qPrint(yyextra->fileName),stateToString(YY_START));}
964 */
965 %%
966
967 static void replaceCommentMarker(yyscan_t yyscanner,const char *s,int len)
968 {
969 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
970 const char *p=s;
971 char c;
972 // copy leading blanks
973 while ((c=*p) && (c==' ' || c=='\t' || c=='\n'))
974 {
975 ADDCHAR(c);
976 yyextra->lineNr += c=='\n';
977 p++;
978 }
979 // replace start of comment marker by blanks and the last character by a *
980 int blanks=0;
981 while ((c=*p) && (c=='/' || c=='!' || c=='#'))
982 {
983 blanks++;
984 p++;
985 if (*p=='<') // comment-after-item marker
986 {
987 blanks++;
988 p++;
989 }
990 if (c=='!') // end after first !
991 {
992 break;
993 }
994 }
995 if (blanks>0)
996 {
997 while (blanks>2)
998 {
999 ADDCHAR(' ');
1000 blanks--;
1001 }
1002 if (blanks>1) ADDCHAR('*');
1003 ADDCHAR(' ');
1004 }
1005 // copy comment line to output
1006 ADDARRAY(p,len-(int)(p-s));
1007 }
1008
1009 static inline int computeIndent(const char *s)
1010 {
1011 int col=0;
1012 static int tabSize=Config_getInt(TAB_SIZE);
1013 const char *p=s;
1014 char c;
1015 while ((c=*p++))
1016 {
1017 if (c==' ') col++;
1018 else if (c=='\t') col+=tabSize-(col%tabSize);
1019 else break;
1020 }
1021 return col;
1022 }
1023
1024 static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len)
1025 {
1026 int tabSize=Config_getInt(TAB_SIZE);
1027 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1028 int i;
1029 if (yyextra->skip) // only add newlines.
1030 {
1031 for (i=0;i<len;i++)
1032 {
1033 switch(s[i])
1034 {
1035 case '\n':
1036 ADDCHAR('\n');
1037 yyextra->lineNr++;
1038 yyextra->col=0;
1039 break;
1040 case '\t':
1041 yyextra->col+=tabSize-(yyextra->col%tabSize);
1042 break;
1043 default:
1044 yyextra->col++;
1045 break;
1046 }
1047 }
1048 }
1049 else if (len>0)
1050 {
1051 ADDARRAY(s,len);
1052 for (i=0;i<len;i++)
1053 {
1054 switch (s[i])
1055 {
1056 case '\n': yyextra->col=0;
1057 //fprintf(stderr,"---> copy %d\n",g_lineNr);
1058 yyextra->lineNr++; break;
1059 case '\t': yyextra->col+=tabSize-(yyextra->col%tabSize); break;
1060 default: yyextra->col++; break;
1061 }
1062 }
1063 }
1064 }
1065
1066 static void clearCommentStack(yyscan_t yyscanner)
1067 {
1068 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1069 while (!yyextra->commentStack.empty()) yyextra->commentStack.pop();
1070 }
1071
1072 static void startCondSection(yyscan_t yyscanner,const QCString §Id)
1073 {
1074 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1075 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1076 CondParser prs;
1077 bool expResult = prs.parse(yyextra->fileName,yyextra->lineNr,sectId);
1078 yyextra->condStack.push(commentcnvYY_CondCtx(yyextra->lineNr,sectId,yyextra->skip));
1079 if (!expResult) // not enabled
1080 {
1081 yyextra->skip=TRUE;
1082 }
1083 }
1084
1085 static void endCondSection(yyscan_t yyscanner)
1086 {
1087 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1088 if (yyextra->condStack.empty())
1089 {
1090 warn(yyextra->fileName,yyextra->lineNr,"Found \\endcond command without matching \\cond");
1091 yyextra->skip=FALSE;
1092 }
1093 else
1094 {
1095 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
1096 yyextra->skip=ctx.skip;
1097 yyextra->condStack.pop();
1098 }
1099 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1100 }
1101
1102 static void handleCondSectionId(yyscan_t yyscanner,const char *expression)
1103 {
1104 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1105 bool oldSkip=yyextra->skip;
1106 startCondSection(yyscanner,QCString(expression));
1107 if ((yyextra->condCtx==CComment || yyextra->readLineCtx==SComment) &&
1108 !oldSkip && yyextra->skip)
1109 {
1110 if (yyextra->lang!=SrcLangExt_Python &&
1111 yyextra->lang!=SrcLangExt_VHDL &&
1112 yyextra->lang!=SrcLangExt_Markdown &&
1113 yyextra->lang!=SrcLangExt_Fortran)
1114 {
1115 ADDCHAR('*');
1116 ADDCHAR('/');
1117 }
1118 }
1119 if (yyextra->readLineCtx==SComment)
1120 {
1121 BEGIN(SComment);
1122 }
1123 else
1124 {
1125 BEGIN(yyextra->condCtx);
1126 }
1127 }
1128
1129 /** copies string \a s with length \a len to the output, while
1130 * replacing any alias commands found in the string.
1131 */
1132 static void replaceAliases(yyscan_t yyscanner,const QCString &s)
1133 {
1134 QCString result = resolveAliasCmd(s);
1135 //printf("replaceAliases(%s)->'%s'\n",s,result.data());
1136 copyToOutput(yyscanner,result.data(),result.length());
1137 }
1138
1139
1140 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
1141 {
1142 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1143 yy_size_t bytesInBuf = yyextra->inBuf->curPos()-yyextra->inBufPos;
1144 yy_size_t bytesToCopy = std::min(max_size,bytesInBuf);
1145 memcpy(buf,yyextra->inBuf->data()+yyextra->inBufPos,bytesToCopy);
1146 yyextra->inBufPos+=bytesToCopy;
1147 return bytesToCopy;
1148 }
1149
1150 static void replaceComment(yyscan_t yyscanner,int offset)
1151 {
1152 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1153 if (yyextra->mlBrief || yyextra->skip)
1154 {
1155 copyToOutput(yyscanner,yytext,(int)yyleng);
1156 }
1157 else
1158 {
1159 //printf("replaceComment(%s)\n",yytext);
1160 int i=computeIndent(&yytext[offset]);
1161 if (i==yyextra->blockHeadCol)
1162 {
1163 replaceCommentMarker(yyscanner,yytext,(int)yyleng);
1164 }
1165 else
1166 {
1167 copyToOutput(yyscanner," */",3);
1168 for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
1169 yyextra->inSpecialComment=FALSE;
1170 BEGIN(Scan);
1171 }
1172 }
1173 }
1174
1175 /*! This function does three things:
1176 * -# It converts multi-line C++ style comment blocks (that are aligned)
1177 * to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
1178 * -# It replaces aliases with their definition (see ALIASES)
1179 * -# It handles conditional sections (cond...endcond blocks)
1180 */
1181 void convertCppComments(BufStr *inBuf,BufStr *outBuf,const QCString &fileName)
1182 {
1183 yyscan_t yyscanner;
1184 commentcnvYY_state extra;
1185 commentcnvYYlex_init_extra(&extra,&yyscanner);
1186 #ifdef FLEX_DEBUG
1187 commentcnvYYset_debug(1,yyscanner);
1188 #endif
1189 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1190 //printf("convertCppComments(%s)\n",fileName);
1191 yyextra->inBuf = inBuf;
1192 yyextra->outBuf = outBuf;
1193 yyextra->inBufPos = 0;
1194 yyextra->col = 0;
1195 yyextra->mlBrief = Config_getBool(MULTILINE_CPP_IS_BRIEF);
1196 yyextra->skip = FALSE;
1197 yyextra->fileName = fileName;
1198 yyextra->lang = getLanguageFromFileName(fileName);
1199 yyextra->pythonDocString = FALSE;
1200 yyextra->lineNr = 1;
1201 while (!yyextra->condStack.empty()) yyextra->condStack.pop();
1202 clearCommentStack(yyscanner);
1203 yyextra->vhdl = FALSE;
1204
1205 printlex(yy_flex_debug, TRUE, __FILE__, qPrint(fileName));
1206 yyextra->isFixedForm = FALSE;
1207 if (yyextra->lang==SrcLangExt_Fortran)
1208 {
1209 FortranFormat fmt = convertFileNameFortranParserCode(fileName);
1210 yyextra->isFixedForm = recognizeFixedForm(QCString(inBuf->data()),fmt);
1211 }
1212
1213 if (yyextra->lang==SrcLangExt_Markdown)
1214 {
1215 yyextra->nestingCount=0;
1216 BEGIN(CComment);
1217 yyextra->commentStack.push(yyextra->lineNr);
1218 }
1219 else
1220 {
1221 BEGIN(Scan);
1222 }
1223 yylex(yyscanner);
1224 while (!yyextra->condStack.empty())
1225 {
1226 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
1227 QCString sectionInfo(" ");
1228 if (ctx.sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",ctx.sectionId.stripWhiteSpace().data());
1229 warn(yyextra->fileName,ctx.lineNr,"Conditional section%sdoes not have "
1230 "a corresponding \\endcond command within this file.",sectionInfo.data());
1231 yyextra->condStack.pop();
1232 }
1233 if (yyextra->nestingCount>0 && yyextra->lang!=SrcLangExt_Markdown && yyextra->lang!=SrcLangExt_Fortran)
1234 {
1235 QCString tmp("(probable line reference: ");
1236 bool first = TRUE;
1237 while (!yyextra->commentStack.empty())
1238 {
1239 int lineNr = yyextra->commentStack.top();
1240 if (!first) tmp += ", ";
1241 tmp += QCString().setNum(lineNr);
1242 first = FALSE;
1243 yyextra->commentStack.pop();
1244 }
1245 tmp += ")";
1246 warn(yyextra->fileName,yyextra->lineNr,"Reached end of file while still inside a (nested) comment. "
1247 "Nesting level %d %s",yyextra->nestingCount,tmp.data());
1248 }
1249 yyextra->nestingCount = 0;
1250 if (Debug::isFlagSet(Debug::CommentCnv))
1251 {
1252 yyextra->outBuf->at(yyextra->outBuf->curPos())='\0';
1253 Debug::print(Debug::CommentCnv,0,"-----------\nCommentCnv: %s\n"
1254 "output=[\n%s]\n-----------\n",qPrint(fileName),yyextra->outBuf->data()
1255 );
1256 }
1257 printlex(yy_flex_debug, FALSE, __FILE__, qPrint(fileName));
1258 commentcnvYYlex_destroy(yyscanner);
1259 }
1260
1261
1262 //----------------------------------------------------------------------------
1263
1264 #if USE_STATE2STRING
1265 #include "commentcnv.l.h"
1266 #endif
1267