Doxygen
Loading...
Searching...
No Matches
commentcnv.l
Go to the documentation of this file.
1/*****************************************************************************
2 *
3 * Copyright (C) 1997-2023 by Dimitri van Heesch.
4 *
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.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16%{
17 // redefine buffer size (defaults to 16Kb) to avoid a 'flex scanner push-back overflow' error
18 #undef YY_BUF_SIZE
19 #define YY_BUF_SIZE 10*1024*1024 // 10Mb should be sufficient for a source file
20%}
21
22%option never-interactive
23%option prefix="commentcnvYY"
24%option reentrant
25%option extra-type="struct commentcnvYY_state *"
26%top{
27#include <stdint.h>
28// forward declare yyscan_t to improve type safety
29#define YY_TYPEDEF_YY_SCANNER_T
30struct yyguts_t;
31typedef yyguts_t *yyscan_t;
yyguts_t * yyscan_t
Definition code.l:24
32}
33
34%{
35
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <stack>
40#include <algorithm>
41#include <deque>
42#include <string_view>
43
44#include "debug.h"
45#include "message.h"
46#include "config.h"
47#include "doxygen.h"
48#include "util.h"
49#include "aliases.h"
50#include "condparser.h"
51#include "fileinfo.h"
52#include "stringutil.h"
53#include "regex.h"
54#include "section.h"
55
56#include <assert.h>
57
58#define YY_NO_INPUT 1
59#define YY_NO_UNISTD_H 1
60
62{
63 commentcnvYY_CondCtx(int line,const QCString &id,bool b)
64 : lineNr(line),sectionId(id), skip(b) {}
65 int lineNr;
67 bool skip;
68};
69
71{
72 CommentCtx(int line)
73 : lineNr(line) {}
74 int lineNr;
75};
76
93
95{
96 commentcnvYY_state(const std::string *i,std::string &o) : inBuf(i), outBuf(o) {}
97 const std::string *inBuf;
98 std::string &outBuf;
99 int inBufPos = 0;
100 int col = 0;
101 int blockHeadCol = 0; // column at which the start of a special comment block was found
102 int insertCommentCol = 0; // column at which an include or snippet command was found
104 int readLineCtx = 0;
105 int includeCtx = 0;
106 int raiseLevel = 0;
110 bool skip = FALSE;
112 int lineNr = 0;
113 int condCtx = 0;
114 std::stack<commentcnvYY_CondCtx> condStack;
115 std::stack<int> commentStack;
121 int charContext = 0;
122 int javaBlock = 0;
124 bool inVerbatim = false;
126 bool firstIncludeLine = false;
130 int blockCount = 0;
136 bool vhdl = FALSE; // for VHDL old style --! comment
137 SrcLangExt lang = SrcLangExt::Unknown;
138 bool isFixedForm = FALSE; // For Fortran
139 std::deque<std::unique_ptr<commentcnv_FileState>> includeStack;
140 std::vector<std::string> expandedAliases;
143};
144
145[[maybe_unused]] static const char *stateToString(int state);
146static inline int computeIndent(const char *s);
147
148static void replaceCommentMarker(yyscan_t yyscanner,std::string_view s);
149static inline void copyToOutput(yyscan_t yyscanner,std::string_view s);
150static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len);
151static void startCondSection(yyscan_t yyscanner,const QCString &sectId);
152static void endCondSection(yyscan_t yyscanner);
153static void handleCondSectionId(yyscan_t yyscanner,const char *expression);
154static void replaceAliases(yyscan_t yyscanner,std::string_view s,bool replaceComment=false);
155static int yyread(yyscan_t yyscanner,char *buf,int max_size);
156static void replaceComment(yyscan_t yyscanner,int offset);
157static void clearCommentStack(yyscan_t yyscanner);
158static bool readIncludeFile(yyscan_t yyscanner,const QCString &inc,const QCString &blockId);
159static void insertCommentStart(yyscan_t yyscanner);
160static bool parseIncludeOptions(yyscan_t yyscanner,std::string_view s);
161
162#undef YY_INPUT
163#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
164
165// otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
166static inline const char *getLexerFILE() {return __FILE__;}
167#include "doxygen_lex.h"
168
This is an alternative implementation of QCString.
Definition qcstring.h:101
static void startCondSection(yyscan_t yyscanner, const QCString &sectId)
static void copyToOutput(yyscan_t yyscanner, std::string_view s)
static int computeIndent(const char *s)
static void handleCondSectionId(yyscan_t yyscanner, const char *expression)
static void endCondSection(yyscan_t yyscanner)
static void replaceComment(yyscan_t yyscanner, int offset)
static void insertCommentStart(yyscan_t yyscanner)
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
static const char * stateToString(int state)
static void replaceCommentMarker(yyscan_t yyscanner, std::string_view s)
static void replaceAliases(yyscan_t yyscanner, std::string_view s, bool replaceComment=false)
copies string s with length len to the output, while replacing any alias commands found in the string...
static void clearCommentStack(yyscan_t yyscanner)
static const char * getLexerFILE()
Definition commentcnv.l:166
static bool readIncludeFile(yyscan_t yyscanner, const QCString &inc, const QCString &blockId)
static bool parseIncludeOptions(yyscan_t yyscanner, std::string_view s)
Token literal values and constants.
Definition CharStream.h:12
#define FALSE
Definition qcstring.h:34
Some helper functions for std::string.
CommentCtx(int line)
Definition commentcnv.l:72
std::string fileBuf
Definition commentcnv.l:86
YY_BUFFER_STATE bufState
Definition commentcnv.l:80
const std::string * oldFileBuf
Definition commentcnv.l:87
commentcnvYY_CondCtx(int line, const QCString &id, bool b)
Definition commentcnv.l:63
std::string & outBuf
Definition commentcnv.l:98
std::deque< std::unique_ptr< commentcnv_FileState > > includeStack
Definition commentcnv.l:139
QCString snippetFileName
Definition commentcnv.l:141
std::vector< std::string > expandedAliases
Definition commentcnv.l:140
std::stack< commentcnvYY_CondCtx > condStack
Definition commentcnv.l:114
const std::string * inBuf
Definition commentcnv.l:97
commentcnvYY_state(const std::string *i, std::string &o)
Definition commentcnv.l:96
std::stack< int > commentStack
Definition commentcnv.l:115
SrcLangExt
Definition types.h:207
A bunch of utility functions.
169%}
170
171MAILADDR ("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\-]+
172
173%option noyywrap
174
175%x Scan
176%x SkipString
177%x SkipVerbString
178%x SkipChar
179%x SkipLang
180%x SComment
181%x CComment
182%x CNComment
183%x Verbatim
184%x VerbatimCode
185%x ReadLine
186%x CopyLine
187%x CondLine
188%x ReadAliasArgs
189%x IncludeDoc
190%x SnippetDoc
191%x SnippetDocTag
192%x IncludeFile
193
194CMD [\\@]
195 //- start: NUMBER -------------------------------------------------------------------------
196 // Note same defines in code.l: keep in sync
197DECIMAL_INTEGER [1-9][0-9']*[0-9]?[uU]?[lL]?[lL]?
198HEXADECIMAL_INTEGER "0"[xX][0-9a-zA-Z']+[0-9a-zA-Z]?
199OCTAL_INTEGER "0"[0-7][0-7']+[0-7]?
200BINARY_INTEGER "0"[bB][01][01']*[01]?
201INTEGER_NUMBER {DECIMAL_INTEGER}|{HEXADECIMAL_INTEGER}|{OCTAL_INTEGER}|{BINARY_INTEGER}
202
203FP_SUF [fFlL]
204
205DIGIT_SEQ [0-9][0-9']*[0-9]?
206FRAC_CONST {DIGIT_SEQ}"."|{DIGIT_SEQ}?"."{DIGIT_SEQ}
207FP_EXP [eE][+-]?{DIGIT_SEQ}
208DEC_FP1 {FRAC_CONST}{FP_EXP}?{FP_SUF}?
209DEC_FP2 {DIGIT_SEQ}{FP_EXP}{FP_SUF}
210
211HEX_DIGIT_SEQ [0-9a-fA-F][0-9a-fA-F']*[0-9a-fA-F]?
212HEX_FRAC_CONST {HEX_DIGIT_SEQ}"."|{HEX_DIGIT_SEQ}?"."{HEX_DIGIT_SEQ}
213BIN_EXP [pP][+-]?{DIGIT_SEQ}
214HEX_FP1 "0"[xX]{HEX_FRAC_CONST}{BIN_EXP}{FP_SUF}?
215HEX_FP2 "0"[xX]{HEX_DIGIT_SEQ}{BIN_EXP}{FP_SUF}?
216
217FLOAT_DECIMAL {DEC_FP1}|{DEC_FP2}
218FLOAT_HEXADECIMAL {HEX_FP1}|{HEX_FP2}
219FLOAT_NUMBER {FLOAT_DECIMAL}|{FLOAT_HEXADECIMAL}
220NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
221
222FILEICHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+=&#@]
223FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+=&#@]
224FILECHARS {FILEICHAR}*{FILEECHAR}+
225HFILEMASK {FILEICHAR}*("."{FILEICHAR}+)+{FILECHARS}*
226VFILEMASK {FILECHARS}("."{FILECHARS})*
227FILEMASK {VFILEMASK}|{HFILEMASK}
228
229B [ \t]
230
231OPTS "{"[^}]*"}"{B}*
232
233 //- end: NUMBER ---------------------------------------------------------------------------
234
235 // C start comment
236CCS "/\*"
237 // C end comment
238CCE "*\/"
239 // Cpp comment
240CPPC "/\/"
241
242 // Optional any character
243ANYopt .*
244 // Optional white space
245WSopt [ \t\r]*
246 // readline non special
247RLopt [^\\@<\n\*\/`]*
248RL [^\\@<\n\*\/`]+
249 // Optional slash
250SLASHopt [/]*
251
253
254<Scan>{NUMBER} { //Note similar code in code.l
255 if (yyextra->lang!=SrcLangExt::Cpp) REJECT;
256 copyToOutput(yyscanner,yytext,yyleng);
257 }
258<Scan>[^"'!\/\n\\#,\-=; \t@$]* { /* eat anything that is not " / , or \n */
259 copyToOutput(yyscanner,yytext,yyleng);
260 }
261<Scan>[,= ;\t] { /* eat , so we have a nice separator in long initialization lines */
262 copyToOutput(yyscanner,yytext,yyleng);
263 }
264<Scan>"'''"! |
265<Scan>"\"\"\""! { /* start of python long comment */
266 if (yyextra->lang!=SrcLangExt::Python)
267 {
268 REJECT;
269 }
270 else
271 {
272 yyextra->pythonDocString = TRUE;
273 yyextra->pythonDocStringChar = yytext[0];
274 yyextra->nestingCount=1;
275 clearCommentStack(yyscanner); /* to be on the save side */
276 copyToOutput(yyscanner,yytext,yyleng);
277 BEGIN(CComment);
278 yyextra->commentStack.push(yyextra->lineNr);
279 }
280 }
#define TRUE
Definition qcstring.h:37
281<Scan>"'''" |
282<Scan>"\"\"\"" { /* start of python long comment */
283 if (yyextra->lang!=SrcLangExt::Python)
284 {
285 REJECT;
286 }
287 else if (Config_getBool(PYTHON_DOCSTRING))
288 {
289 REJECT;
290 }
291 else
292 { /* handle as if """! */
293 yyextra->pythonDocString = TRUE;
294 yyextra->pythonDocStringChar = yytext[0];
295 yyextra->nestingCount=1;
296 clearCommentStack(yyscanner); /* to be on the save side */
297 copyToOutput(yyscanner,yytext,yyleng);
298 BEGIN(CComment);
299 yyextra->commentStack.push(yyextra->lineNr);
300 }
301 }
#define Config_getBool(name)
Definition config.h:33
302<Scan>{B}*![><!]/.*\n {
303 if (yyextra->lang!=SrcLangExt::Fortran)
304 {
305 REJECT;
306 }
307 else
308 {
309 yyextra->nestingCount=0; // Fortran doesn't have an end comment
310 clearCommentStack(yyscanner); /* to be on the save side */
311 yyextra->specialComment=true;
312 copyToOutput(yyscanner,yytext,yyleng);
313 yyextra->blockHeadCol=yyextra->col-2;
314 BEGIN(CComment);
315 yyextra->commentStack.push(yyextra->lineNr);
316 }
317 }
318<Scan>[Cc\*][><!]/.*\n {
319 if (yyextra->lang!=SrcLangExt::Fortran)
320 {
321 REJECT;
322 }
323 else
324 {
325 /* check for fixed format; we might have some conditional as part of multiline if like C<5 .and. & */
326 if (yyextra->isFixedForm && (yyextra->col == 0))
327 {
328 yyextra->nestingCount=0; // Fortran doesn't have an end comment
329 clearCommentStack(yyscanner); /* to be on the save side */
330 yyextra->specialComment=true;
331 copyToOutput(yyscanner,yytext,yyleng);
332 yyextra->blockHeadCol=yyextra->col-1;
333 BEGIN(CComment);
334 yyextra->commentStack.push(yyextra->lineNr);
335 }
336 else
337 {
338 REJECT;
339 }
340 }
341 }
342<Scan>!.*\n {
343 if (yyextra->lang!=SrcLangExt::Fortran)
344 {
345 REJECT;
346 }
347 else
348 {
349 copyToOutput(yyscanner,yytext,yyleng);
350 }
351 }
352<Scan>[Cc\*].*\n {
353 if (yyextra->lang!=SrcLangExt::Fortran)
354 {
355 REJECT;
356 }
357 else
358 {
359 if (yyextra->col == 0)
360 {
361 copyToOutput(yyscanner,yytext,yyleng);
362 }
363 else
364 {
365 REJECT;
366 }
367 }
368 }
369<Scan>[$]?"@\"" { /* start of an interpolated verbatim C# string */
370 if (yyextra->lang!=SrcLangExt::CSharp) REJECT
371 copyToOutput(yyscanner,yytext,yyleng);
372 yyextra->stringContext = YY_START;
373 BEGIN(SkipVerbString);
374 }
375<Scan>"\"" { /* start of a string */
376 copyToOutput(yyscanner,yytext,yyleng);
377 yyextra->stringContext = YY_START;
378 BEGIN(SkipString);
379 }
380<Scan>' {
381 copyToOutput(yyscanner,yytext,yyleng);
382 yyextra->charContext = YY_START;
383 if (yyextra->lang!=SrcLangExt::VHDL)
384 {
385 BEGIN(SkipChar);
386 }
387 }
388<Scan>\n { /* new line */
389 copyToOutput(yyscanner,yytext,yyleng);
390 }
391<Scan>{CPPC}"!"/.*\n[ \t]*{CPPC}[\/!][^\/] | /* start C++ style special comment block */
392<Scan>({CPPC}"/"[/]*)/[^/].*\n[ \t]*{CPPC}[\/!][^\/] { /* start C++ style special comment block */
393 if (yyextra->mlBrief)
394 {
395 REJECT; // bail out if we do not need to convert
396 }
397 else
398 {
399 int i=3;
400 if (yytext[2]=='/')
401 {
402 while (i<(int)yyleng && yytext[i]=='/') i++;
403 }
404 yyextra->blockHeadCol=yyextra->col+1;
405 if (yytext[2] == '!')
406 {
407 copyToOutput(yyscanner,"/*!");
408 }
409 else
410 {
411 copyToOutput(yyscanner,"/**");
412 }
413 if (i<yyleng) replaceAliases(yyscanner,yytext+i);
414 yyextra->inSpecialComment=TRUE;
415 //BEGIN(SComment);
416 yyextra->readLineCtx=SComment;
417 BEGIN(ReadLine);
418 }
419 }
420<Scan>{CPPC}"##Documentation"{ANYopt}/\n { /* Start of Rational Rose ANSI C++ comment block */
421 if (yyextra->mlBrief) REJECT;
422 int i=17; //=strlen("//##Documentation");
423 yyextra->blockHeadCol=yyextra->col+1;
424 copyToOutput(yyscanner,"/**");
425 if (i<yyleng) replaceAliases(yyscanner,yytext+i);
426 yyextra->inRoseComment=TRUE;
427 BEGIN(SComment);
428 }
429<Scan>{CPPC}[!\/]/.*\n[ \t]*{CPPC}[|\/][ \t]*[@\\]"}" { // next line contains an end marker, see bug 752712
430 yyextra->inSpecialComment=yytext[2]=='/' || yytext[2]=='!';
431 if (yyextra->inSpecialComment)
432 {
433 yyextra->blockHeadCol=yyextra->col+1;
434 }
435 copyToOutput(yyscanner,yytext,yyleng);
436 yyextra->readLineCtx=YY_START;
437 BEGIN(ReadLine);
438 }
439<Scan>{CPPC}[!/]/.*\n { /* one line special C++ comment */
440 yyextra->inSpecialComment=true;
441 yyextra->blockHeadCol=yyextra->col+1;
442 yyextra->insertCppCommentMarker=true;
443 copyToOutput(yyscanner,yytext,yyleng);
444 yyextra->readLineCtx=YY_START;
445 BEGIN(ReadLine);
446 }
447<Scan>{CPPC}/.*\n { /* one line normal C++ comment */
448 yyextra->inSpecialComment=false;
449 copyToOutput(yyscanner,yytext,yyleng);
450 yyextra->readLineCtx=YY_START;
451 BEGIN(CopyLine);
452 }
453<Scan>{CCS}{CCE} { /* avoid matching next rule for empty C comment, see bug 711723 */
454 copyToOutput(yyscanner,yytext,yyleng);
455 }
456<Scan>{CCS}[*!]? { /* start of a C comment */
457 if (yyextra->lang==SrcLangExt::Python)
458 {
459 REJECT;
460 }
461 yyextra->specialComment=(int)yyleng==3;
462 yyextra->nestingCount=1;
463 clearCommentStack(yyscanner); /* to be on the save side */
464 copyToOutput(yyscanner,yytext,yyleng);
465 if (yyextra->specialComment)
466 {
467 yyextra->blockHeadCol=0;
468 BEGIN(CComment);
469 }
470 else
471 {
472 BEGIN(CNComment);
473 }
474 yyextra->commentStack.push(yyextra->lineNr);
475 }
476<Scan>"#"[^\n]*\n {
477 if (yyextra->lang!=SrcLangExt::PHP)
478 {
479 REJECT;
480 }
481 copyToOutput(yyscanner,yytext,yyleng);
482 }
483<Scan>"#"("#")? {
484 if (yyextra->lang!=SrcLangExt::Python)
485 {
486 REJECT;
487 }
488 else
489 {
490 yyextra->nestingCount=0; // Python doesn't have an end comment for #
491 clearCommentStack(yyscanner); /* to be on the save side */
492 yyextra->specialComment=(int)yyleng==2;
493 if (yyextra->specialComment)
494 {
495 yyextra->blockHeadCol=yyextra->col;
496 }
497 yyextra->commentStack.push(yyextra->lineNr);
498 copyToOutput(yyscanner,yytext,yyleng);
499 BEGIN(CComment);
500 }
501 }
502<Scan>"--"[^!][^\n]* {
503 if (yyextra->lang!=SrcLangExt::VHDL)
504 {
505 REJECT;
506 }
507 else
508 {
509 copyToOutput(yyscanner,yytext,yyleng);
510 }
511 }
512<Scan>"--!" {
513 if (yyextra->lang!=SrcLangExt::VHDL)
514 {
515 REJECT;
516 }
517 else
518 {
519 yyextra->specialComment=true;
520 yyextra->blockHeadCol=yyextra->col;
521 yyextra->vhdl = TRUE;
522 yyextra->nestingCount=0; // VHDL doesn't have an end comment
523 clearCommentStack(yyscanner); /* to be on the save side */
524 yyextra->commentStack.push(yyextra->lineNr);
525 copyToOutput(yyscanner,yytext,yyleng);
526 BEGIN(CComment);
527 }
528 }
529<Scan>{B}*![><!] {
530 if (yyextra->lang!=SrcLangExt::Fortran)
531 {
532 REJECT;
533 }
534 else
535 {
536 yyextra->nestingCount=0; // Fortran doesn't have an end comment
537 clearCommentStack(yyscanner); /* to be on the save side */
538 yyextra->specialComment=true;
539 yyextra->blockHeadCol=yyextra->col;
540 yyextra->commentStack.push(yyextra->lineNr);
541 copyToOutput(yyscanner,yytext,yyleng);
542 BEGIN(CComment);
543 }
544 }
545<CComment,CNComment,ReadLine,IncludeFile>{MAILADDR} |
546<CComment,CNComment,ReadLine,IncludeFile>"<"{MAILADDR}">" { // Mail address, to prevent seeing e.g x@code-factory.org as start of a code block
547 copyToOutput(yyscanner,yytext,yyleng);
548 }
549<CComment,IncludeFile>"{"[ \t]*"@code"/[ \t\n] {
550 copyToOutput(yyscanner,"@iliteral{code}");
551 yyextra->lastCommentContext = YY_START;
552 yyextra->javaBlock=1;
553 yyextra->blockName=QCString("end")+&yytext[1];
554 yyextra->inVerbatim=true;
555 BEGIN(VerbatimCode);
556 }
557<CComment,IncludeFile>"{"[ \t]*"@literal"/[ \t\n] {
558 copyToOutput(yyscanner,"@iliteral");
559 yyextra->lastCommentContext = YY_START;
560 yyextra->javaBlock=1;
561 yyextra->blockName=QCString("end")+&yytext[1];
562 yyextra->inVerbatim=true;
563 BEGIN(VerbatimCode);
564 }
565<CComment,ReadLine,IncludeFile>{CMD}"ilinebr"[ \t]+("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
566 if (!Config_getBool(MARKDOWN_SUPPORT))
567 {
568 REJECT;
569 }
570 copyToOutput(yyscanner,yytext,yyleng);
571 yyextra->lastCommentContext = YY_START;
572 yyextra->javaBlock=0;
573 yyextra->blockName=QCString(yytext).stripWhiteSpace().right(3); // take the ``` or ~~~ part
574 yyextra->inVerbatim=true;
575 BEGIN(VerbatimCode);
576 }
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:245
QCString right(size_t len) const
Definition qcstring.h:219
577<CComment,ReadLine,IncludeFile>^[ \t]*("```"[`]*|"~~~"[~]*) { /* start of markdown code block */
578 if (!Config_getBool(MARKDOWN_SUPPORT))
579 {
580 REJECT;
581 }
582 copyToOutput(yyscanner,yytext,yyleng);
583 yyextra->lastCommentContext = YY_START;
584 yyextra->javaBlock=0;
585 yyextra->blockName=QCString(yytext).stripWhiteSpace().left(3); // take the ``` or ~~~ part
586 yyextra->inVerbatim=true;
587 BEGIN(VerbatimCode);
588 }
QCString left(size_t len) const
Definition qcstring.h:214
589<CComment,ReadLine,IncludeFile>[\\@]("dot"|"code"|"msc"|"startuml")/[^a-z_A-Z0-9] { /* start of a verbatim block */
590 copyToOutput(yyscanner,yytext,yyleng);
591 yyextra->lastCommentContext = YY_START;
592 yyextra->javaBlock=0;
593 if (qstrcmp(&yytext[1],"startuml")==0)
594 {
595 yyextra->blockName="enduml";
596 }
597 else
598 {
599 yyextra->blockName=QCString("end")+&yytext[1];
600 }
601 yyextra->inVerbatim=true;
602 BEGIN(VerbatimCode);
603 }
int qstrcmp(const char *str1, const char *str2)
Definition qcstring.h:69
604<CComment,ReadLine,IncludeFile>[\\@]("f$"|"f["|"f{"|"f(") {
605 copyToOutput(yyscanner,yytext,yyleng);
606 yyextra->blockName=&yytext[1];
607 if (yyextra->blockName.at(1)=='[')
608 {
609 yyextra->blockName.at(1)=']';
610 }
611 else if (yyextra->blockName.at(1)=='{')
612 {
613 yyextra->blockName.at(1)='}';
614 }
615 else if (yyextra->blockName.at(1)=='(')
616 {
617 yyextra->blockName.at(1)=')';
618 }
619 yyextra->lastCommentContext = YY_START;
620 yyextra->inVerbatim=true;
621 BEGIN(Verbatim);
622 }
623<CComment,ReadLine,IncludeFile>"<!--!" { /* HTML comment doxygen command*/
624 if (yyextra->inVerbatim) REJECT;
625 //copyToOutput(yyscanner," ",5);
626 yyextra->inHtmlDoxygenCommand=true;
627 }
628<CComment,ReadLine,IncludeFile>"-->" { /* potential end HTML comment doxygen command*/
629 if (yyextra->inHtmlDoxygenCommand)
630 {
631 yyextra->inHtmlDoxygenCommand=false;
632 }
633 else
634 {
635 copyToOutput(yyscanner,yytext,yyleng);
636 }
637 }
638<CComment,ReadLine,IncludeFile>"<!--" { /* HTML comment */
639 copyToOutput(yyscanner,yytext,yyleng);
640 yyextra->blockName="-->";
641 yyextra->lastCommentContext = YY_START;
642 yyextra->inVerbatim=true;
643 BEGIN(Verbatim);
644 }
645<CComment,ReadLine,IncludeFile>[\\@]("verbatim"|"iliteral"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"rtfonly"|"manonly")/[^a-z_A-Z0-9] { /* start of a verbatim block */
646 copyToOutput(yyscanner,yytext,yyleng);
647 yyextra->blockName=QCString("end")+&yytext[1];
648 yyextra->lastCommentContext = YY_START;
649 yyextra->inVerbatim=true;
650 BEGIN(Verbatim);
651 }
652<Scan>"\\\"" { /* escaped double quote */
653 copyToOutput(yyscanner,yytext,yyleng);
654 }
655<Scan>"\\\\" { /* escaped backslash */
656 copyToOutput(yyscanner,yytext,yyleng);
657 }
658<Scan>. { /* any other character */
659 copyToOutput(yyscanner,yytext,yyleng);
660 }
661<Verbatim>[\\@]("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}"|"f)") { /* end of verbatim block */
662 copyToOutput(yyscanner,yytext,yyleng);
663 if (&yytext[1]==yyextra->blockName) // end of command or formula
664 {
665 yyextra->inVerbatim=false;
666 BEGIN(yyextra->lastCommentContext);
667 }
668 }
669<Verbatim>"-->" {
670 copyToOutput(yyscanner,yytext,yyleng);
671 if (yytext==yyextra->blockName)
672 {
673 yyextra->inVerbatim=false;
674 BEGIN(yyextra->lastCommentContext);
675 }
676 }
677<VerbatimCode>"{" {
678 if (yyextra->javaBlock==0)
679 {
680 REJECT;
681 }
682 else
683 {
684 yyextra->javaBlock++;
685 copyToOutput(yyscanner,yytext,yyleng);
686 }
687 }
688<VerbatimCode>"}" {
689 if (yyextra->javaBlock==0)
690 {
691 REJECT;
692 }
693 else
694 {
695 yyextra->javaBlock--;
696 if (yyextra->javaBlock==0)
697 {
698 copyToOutput(yyscanner," @endiliteral ");
699 yyextra->inVerbatim=false;
700 BEGIN(yyextra->lastCommentContext);
701 }
702 else
703 {
704 copyToOutput(yyscanner,yytext,yyleng);
705 }
706 }
707 }
708<VerbatimCode>("```"[`]*|"~~~"[~]*) { /* end of markdown code block */
709 copyToOutput(yyscanner,yytext,yyleng);
710 if (yytext[0]==yyextra->blockName[0])
711 {
712 yyextra->inVerbatim=false;
713 BEGIN(yyextra->lastCommentContext);
714 }
715 }
716<VerbatimCode>[\\@]("enddot"|"endcode"|"endmsc"|"enduml")/("{")? { /* end of verbatim block */
717 copyToOutput(yyscanner,yytext,yyleng);
718 if (&yytext[1]==yyextra->blockName)
719 {
720 yyextra->inVerbatim=false;
721 BEGIN(yyextra->lastCommentContext);
722 }
723 }
724<VerbatimCode>^[ \t]*{CPPC}[\!\/]? { /* skip leading comments */
725 if (!yyextra->inSpecialComment || yyextra->mlBrief)
726 {
727 copyToOutput(yyscanner,yytext,yyleng);
728 }
729 else
730 {
731 int l=0;
732 while (yytext[l]==' ' || yytext[l]=='\t')
733 {
734 l++;
735 }
736 copyToOutput(yyscanner,yytext,l);
737 if (yyleng-l==3) // ends with //! or ///
738 {
739 copyToOutput(yyscanner," * ");
740 }
741 else // ends with //
742 {
743 copyToOutput(yyscanner,"//");
744 }
745 }
746 }
747<Verbatim,VerbatimCode>[^`~@\/\-\\\n{}]* { /* any character not a backslash or new line or } */
748 copyToOutput(yyscanner,yytext,yyleng);
749 }
750<Verbatim,VerbatimCode>\n { /* new line in verbatim block */
751 copyToOutput(yyscanner,yytext,yyleng);
752 if (yyextra->lastCommentContext == IncludeFile)
753 {
754 insertCommentStart(yyscanner);
755 }
756 }
757<Verbatim>^[ \t]*{CPPC}[/!] {
758 if (yyextra->blockName=="enddot" || yyextra->blockName=="endmsc" || yyextra->blockName=="enduml" || yyextra->blockName.at(0)=='f')
759 {
760 // see bug 487871, strip /// from dot images and formulas.
761 int l=0;
762 while (yytext[l]==' ' || yytext[l]=='\t')
763 {
764 l++;
765 }
766 copyToOutput(yyscanner,yytext,l);
767 copyToOutput(yyscanner," ");
768 }
769 else // even slashes are verbatim (e.g. \verbatim, \code)
770 {
771 REJECT;
772 }
773 }
774<Verbatim,VerbatimCode>. { /* any other character */
775 copyToOutput(yyscanner,yytext,yyleng);
776 }
777<SkipString>\\. { /* escaped character in string */
778 if (yyextra->lang==SrcLangExt::Fortran || yyextra->lang==SrcLangExt::VHDL)
779 {
780 unput(yytext[1]);
781 copyToOutput(yyscanner,yytext,1);
782 }
783 else
784 {
785 copyToOutput(yyscanner,yytext,yyleng);
786 }
787 }
788<SkipString>"\"" { /* end of string */
789 copyToOutput(yyscanner,yytext,yyleng);
790 BEGIN(yyextra->stringContext);
791 }
792<SkipString>. { /* any other string character */
793 copyToOutput(yyscanner,yytext,yyleng);
794 }
795<SkipString>\n { /* new line inside string (illegal for some compilers) */
796 copyToOutput(yyscanner,yytext,yyleng);
797 }
798<SkipVerbString>[^"\n]+ {
799 copyToOutput(yyscanner,yytext,yyleng);
800 }
801<SkipVerbString>\"\" { // escaped quote
802 copyToOutput(yyscanner,yytext,yyleng);
803 }
804<SkipVerbString>"\"" { /* end of string */
805 copyToOutput(yyscanner,yytext,yyleng);
806 BEGIN(yyextra->stringContext);
807 }
808<SkipVerbString>. {
809 copyToOutput(yyscanner,yytext,yyleng);
810 }
811<SkipVerbString>\n {
812 copyToOutput(yyscanner,yytext,yyleng);
813 }
814<SkipChar>\\. { /* escaped character */
815 if (yyextra->lang==SrcLangExt::Fortran || yyextra->lang==SrcLangExt::VHDL)
816 {
817 unput(yytext[1]);
818 copyToOutput(yyscanner,yytext,1);
819 }
820 else
821 {
822 copyToOutput(yyscanner,yytext,yyleng);
823 }
824 }
825<SkipChar>' { /* end of character literal */
826 copyToOutput(yyscanner,yytext,yyleng);
827 BEGIN(yyextra->charContext);
828 }
829<SkipChar>. { /* any other string character */
830 copyToOutput(yyscanner,yytext,yyleng);
831 }
832<SkipChar>\n { /* new line character */
833 copyToOutput(yyscanner,yytext,yyleng);
834 }
835
836<CComment,CNComment>[^ `~<\\!@*\n{\"'\/-]* { /* anything that is not a '*' or command */
837 copyToOutput(yyscanner,yytext,yyleng);
838 }
839<CComment,CNComment>^{B}*"*"+[^*\/<\\@\n{\"]* { /* stars without slashes */
840 if (yyextra->lang==SrcLangExt::Markdown) REJECT;
841 yyextra->col = computeIndent(yytext);
842 if (yyextra->col>yyextra->blockHeadCol)
843 {
844 //printf("new blockHeadCol=%d\n",yyextra->blockHeadCol);
845 yyextra->blockHeadCol=yyextra->col;
846 }
847 copyToOutput(yyscanner,yytext,yyleng);
848 }
849<CComment>"'''" |
850<CComment>"\"\"\"" { /* end of Python docstring */
851 if (yyextra->lang!=SrcLangExt::Python)
852 {
853 REJECT;
854 }
855 else if (yyextra->pythonDocStringChar != yytext[0])
856 {
857 copyToOutput(yyscanner,yytext,yyleng);
858 }
859 else
860 {
861 yyextra->nestingCount--;
862 yyextra->pythonDocString = FALSE;
863 yyextra->pythonDocStringChar = '\0';
864 copyToOutput(yyscanner,yytext,yyleng);
865 BEGIN(Scan);
866 }
867 }
868<CComment,CNComment>\n { /* new line in comment */
869 copyToOutput(yyscanner,yytext,yyleng);
870 /* in case of Fortran always end of comment */
871 if (yyextra->lang==SrcLangExt::Fortran)
872 {
873 BEGIN(Scan);
874 }
875 }
876<CComment,CNComment>"/""/"+/"*/" { /* we are already in C-comment so not a start of a nested comment but
877 * just the end of the comment (the end part is handled later). */
878 copyToOutput(yyscanner,yytext,yyleng);
879 }
880<CComment,CNComment>"/"+"*" { /* nested C comment */
881 if (yyextra->lang==SrcLangExt::Python ||
882 yyextra->lang==SrcLangExt::Markdown)
883 {
884 REJECT;
885 }
886 yyextra->nestingCount++;
887 yyextra->commentStack.push(yyextra->lineNr);
888 copyToOutput(yyscanner,yytext,yyleng);
889 }
890<CComment,CNComment>^{B}*"*"+"/" |
891<CComment,CNComment>"*"+"/" { /* end of C comment */
892 if (yyextra->lang==SrcLangExt::Python ||
893 yyextra->lang==SrcLangExt::Markdown)
894 {
895 REJECT;
896 }
897 else
898 {
899 copyToOutput(yyscanner,yytext,yyleng);
900 yyextra->nestingCount--;
901 if (yyextra->nestingCount<=0)
902 {
903 BEGIN(Scan);
904 }
905 else
906 {
907 //yyextra->nestingCount--;
908 yyextra->commentStack.pop();
909 }
910 }
911 }
912 /* Python an VHDL share CComment,CNComment, so special attention for ending comments is required */
913<CComment,CNComment>"\n"/[ \t]*"#" {
914 if (yyextra->lang!=SrcLangExt::VHDL)
915 {
916 REJECT;
917 }
918 else
919 {
920 if (yyextra->vhdl) // inside --! comment
921 {
922 yyextra->vhdl = FALSE;
923 copyToOutput(yyscanner,yytext,yyleng);
924 BEGIN(Scan);
925 }
926 else // C-type comment
927 {
928 REJECT;
929 }
930 }
931 }
932<CComment,CNComment>"\n"/[ \t]*"-" {
933 if (yyextra->lang!=SrcLangExt::Python || yyextra->pythonDocString)
934 {
935 REJECT;
936 }
937 else
938 {
939 copyToOutput(yyscanner,yytext,yyleng);
940 BEGIN(Scan);
941 }
942 }
943<CComment,CNComment>"\n"/[ \t]*[^ \t#\-] {
944 if (yyextra->lang==SrcLangExt::Python)
945 {
946 if (yyextra->pythonDocString)
947 {
948 REJECT;
949 }
950 else
951 {
952 copyToOutput(yyscanner,yytext,yyleng);
953 BEGIN(Scan);
954 }
955 }
956 else if (yyextra->lang==SrcLangExt::VHDL)
957 {
958 if (yyextra->vhdl) // inside --! comment
959 {
960 yyextra->vhdl = FALSE;
961 copyToOutput(yyscanner,yytext,yyleng);
962 BEGIN(Scan);
963 }
964 else // C-type comment
965 {
966 REJECT;
967 }
968 }
969 else
970 {
971 REJECT;
972 }
973 }
974 /* removed for bug 674842 (bug was introduced in rev 768)
975<CComment,CNComment>"'" {
976 yyextra->charContext = YY_START;
977 copyToOutput(yyscanner,yytext,yyleng);
978 BEGIN(SkipChar);
979 }
980<CComment,CNComment>"\"" {
981 yyextra->stringContext = YY_START;
982 copyToOutput(yyscanner,yytext,yyleng);
983 BEGIN(SkipString);
984 }
985 */
986<CComment,CNComment>{CMD}"~"[a-z_A-Z-]* { // language switch command
987 if (yyextra->lang!=SrcLangExt::Markdown) REJECT;
988 QCString langId = QCString(yytext).mid(2);
989 if (!langId.isEmpty() &&
990 qstricmp(Config_getEnumAsString(OUTPUT_LANGUAGE),langId)!=0)
991 { // enable language specific section
992 if (!Config_isAvailableEnum(OUTPUT_LANGUAGE,langId))
993 {
994 warn(yyextra->fileName,yyextra->lineNr,
995 "non supported language '{}' specified in '{}'",langId,QCString(yytext).stripWhiteSpace());
996 }
997 BEGIN(SkipLang);
998 }
999 }
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:226
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
#define Config_getEnumAsString(name)
Definition config.h:36
#define Config_isAvailableEnum(name, value)
Definition config.h:45
#define warn(file, line, fmt,...)
Definition message.h:97
int qstricmp(const char *s1, const char *s2)
Definition qcstring.cpp:442
std::string_view stripWhiteSpace(std::string_view s)
Given a string view s, returns a new, narrower view on that string, skipping over any leading or trai...
Definition stringutil.h:72
1000<CComment,CNComment>{CMD}{CMD} |
1001<CComment,CNComment>. {
1002 copyToOutput(yyscanner,yytext,yyleng);
1003 }
1004<SkipLang>{CMD}"~"[a-zA-Z-]* { /* language switch */
1005 QCString langId(&yytext[2]);
1006 if (!langId.isEmpty() && !Config_isAvailableEnum(OUTPUT_LANGUAGE,langId))
1007 {
1008 warn(yyextra->fileName,yyextra->lineNr,
1009 "non supported language '{}' specified in '{}'",langId,QCString(yytext).stripWhiteSpace());
1010 }
1011 else if (langId.isEmpty() ||
1012 qstricmp(Config_getEnumAsString(OUTPUT_LANGUAGE),langId)==0)
1013 { // enable language specific section
1014 BEGIN(CComment);
1015 }
1016 }
1017<SkipLang>[^*@\\\n]* { /* any character not a *, @, backslash or new line */
1018 }
1019<SkipLang>\n { /* new line in language block, needed for keeping track of line numbers */
1020 copyToOutput(yyscanner,yytext,yyleng);
1021 }
1022<SkipLang>. { /* any other character */
1023 }
1024<SComment>^[ \t]*{CPPC}"/"{SLASHopt}/\n {
1025 replaceComment(yyscanner,0);
1026 }
1027<SComment>\n[ \t]*{CPPC}"/"{SLASHopt}/\n {
1028 replaceComment(yyscanner,1);
1029 }
1030<SComment>^[ \t]*{CPPC}"/"[^\/\n]/.*\n {
1031 replaceComment(yyscanner,0);
1032 yyextra->readLineCtx=YY_START;
1033 BEGIN(ReadLine);
1034 }
1035<SComment>\n[ \t]*{CPPC}[\/!]("<")?[ \t]*[\\@]"}".*\n {
1036 /* See Bug 752712: end the multiline comment when finding a @} or \} command */
1037 copyToOutput(yyscanner," */");
1038 copyToOutput(yyscanner,yytext,yyleng);
1039 yyextra->inSpecialComment=false;
1040 yyextra->inRoseComment=false;
1041 BEGIN(Scan);
1042 }
1043<SComment>\n[ \t]*{CPPC}"/"[^\\@\/\n]/.*\n {
1044 replaceComment(yyscanner,1);
1045 yyextra->readLineCtx=YY_START;
1046 BEGIN(ReadLine);
1047 }
1048<SComment>^[ \t]*{CPPC}"!" | // just //!
1049<SComment>^[ \t]*{CPPC}"!<"/.*\n | // or //!< something
1050<SComment>^[ \t]*{CPPC}"!"[^<]/.*\n { // or //!something
1051 replaceComment(yyscanner,0);
1052 yyextra->readLineCtx=YY_START;
1053 BEGIN(ReadLine);
1054 }
1055<SComment>\n[ \t]*{CPPC}"!" |
1056<SComment>\n[ \t]*{CPPC}"!<"/.*\n |
1057<SComment>\n[ \t]*{CPPC}"!"[^<\n]/.*\n {
1058 replaceComment(yyscanner,1);
1059 yyextra->readLineCtx=YY_START;
1060 BEGIN(ReadLine);
1061 }
1062<SComment>^[ \t]*{CPPC}"##"/.*\n {
1063 if (!yyextra->inRoseComment)
1064 {
1065 REJECT;
1066 }
1067 else
1068 {
1069 replaceComment(yyscanner,0);
1070 yyextra->readLineCtx=YY_START;
1071 BEGIN(ReadLine);
1072 }
1073 }
1074<SComment>\n[ \t]*{CPPC}"##"/.*\n {
1075 if (!yyextra->inRoseComment)
1076 {
1077 REJECT;
1078 }
1079 else
1080 {
1081 replaceComment(yyscanner,1);
1082 yyextra->readLineCtx=YY_START;
1083 BEGIN(ReadLine);
1084 }
1085 }
1086<SComment>\n { /* end of special comment */
1087 copyToOutput(yyscanner," */");
1088 copyToOutput(yyscanner,yytext,yyleng);
1089 yyextra->inSpecialComment=FALSE;
1090 yyextra->inRoseComment=FALSE;
1091 yyextra->insertCppCommentMarker=false;
1092 yyextra->readLineCtx = Scan; // reset, otherwise there will be problems with:
1093 // static void handleCondSectionId
1094 BEGIN(Scan);
1095 }
1096<ReadLine>{CCS}"*" {
1097 copyToOutput(yyscanner,"/&zwj;**");
1098 }
1099<ReadLine>{CCE} {
1100 copyToOutput(yyscanner,"*&zwj;/");
1101 }
1102<ReadLine,CopyLine>"*" {
1103 copyToOutput(yyscanner,yytext,yyleng);
1104 }
1105<ReadLine,CopyLine>{RL} {
1106 copyToOutput(yyscanner,yytext,yyleng);
1107 }
1108<ReadLine,CopyLine>{RL}/{B}{CMD}"ilinebr"{B} {
1109 copyToOutput(yyscanner,yytext,yyleng);
1110 }
1111<ReadLine,CopyLine>{RLopt}/\n {
1112 copyToOutput(yyscanner,yytext,yyleng);
1113 yyextra->insertCppCommentMarker=false;
1114 BEGIN(yyextra->readLineCtx);
1115 }
1116<CComment,CNComment,ReadLine>"\<" { /* escaped html comment */
1117 copyToOutput(yyscanner,yytext,yyleng);
1118 }
1119<CComment,CNComment,ReadLine>[\\@][\\@][~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
1120 copyToOutput(yyscanner,yytext,yyleng);
1121 }
1122
1123<CComment,ReadLine,IncludeFile>[\\@]("include"{OPTS}|"includedoc"{OPTS}*) {
1124 if (!parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)})) REJECT;
1125 yyextra->includeCtx = YY_START;
1126 yyextra->firstIncludeLine = true;
1127 yyextra->insertCommentCol = yyextra->col;
1128 if (!yyextra->insertCppCommentMarker && (yyextra->includeCtx==ReadLine || yyextra->includeCtx==IncludeFile))
1129 {
1130 yyextra->insertCppCommentMarker = yyextra->mlBrief;
1131 }
1132 //printf("blockHeadCol=%d insertCommentCol=%d\n",yyextra->blockHeadCol, yyextra->insertCommentCol);
1133 BEGIN(IncludeDoc);
1134 }
1135<CComment,ReadLine,IncludeFile>[\\@]("snippet"{OPTS}|"snippetdoc"{OPTS}*) {
1136 if (!parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)})) REJECT;
1137 yyextra->includeCtx = YY_START;
1138 yyextra->firstIncludeLine = true;
1139 yyextra->insertCommentCol = yyextra->col;
1140 if (!yyextra->insertCppCommentMarker && (yyextra->includeCtx==ReadLine || yyextra->includeCtx==IncludeFile))
1141 {
1142 yyextra->insertCppCommentMarker = yyextra->mlBrief;
1143 }
1144 //printf("blockHeadCol=%d insertCommentCol=%d\n",yyextra->blockHeadCol, yyextra->insertCommentCol);
1145 BEGIN(SnippetDoc);
1146 }
1147<IncludeDoc,SnippetDoc>{B}*
1148<IncludeDoc>{FILEMASK}|"\""[^\n\"]+"\"" {
1149 QCString fileName=yytext;
1150 if (yytext[0]=='"')
1151 {
1152 fileName=fileName.mid(1,fileName.length()-2); // strip quotes
1153 }
1154 if (readIncludeFile(yyscanner,fileName,""))
1155 {
1156 BEGIN(IncludeFile);
1157 }
1158 else
1159 {
1160 BEGIN(yyextra->includeCtx);
1161 }
1162 }
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:153
1163<SnippetDoc>({FILEMASK}|"\""[^\n\"]+"\""){B}+ {
1164 yyextra->snippetFileName=yytext;
1165 yyextra->snippetFileName=yyextra->snippetFileName.stripWhiteSpace();
1166 if (yyextra->snippetFileName == "this") yyextra->snippetFileName=yyextra->fileName;
1167 yyextra->snippetName = "";
1168 BEGIN(SnippetDocTag);
1169 }
1170<SnippetDocTag>[^\\@\n]+ {
1171 yyextra->snippetName += yytext;
1172 }
1173<SnippetDocTag>{CMD} {
1174 yyextra->snippetName += yytext;
1175 }
1176<SnippetDocTag>(\n|{CMD}"ilinebr") {
1177 for (int i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
1178 yyextra->snippetName = yyextra->snippetName.stripWhiteSpace();
1179 QCString blockId = "["+yyextra->snippetName+"]";
1180 if (readIncludeFile(yyscanner,yyextra->snippetFileName,blockId))
1181 {
1182 BEGIN(IncludeFile);
1183 }
1184 else
1185 {
1186 BEGIN(yyextra->includeCtx);
1187 }
1188 }
1189
1190<IncludeDoc,SnippetDoc>\n {
1191 copyToOutput(yyscanner,yytext,yyleng);
1192 insertCommentStart(yyscanner);
1193 // missing file name
1194 //warn(yyextra->fileName,yyextra->lineNr,"Found \\include{{doc}} command without valid file name argument");
1195 BEGIN(yyextra->includeCtx);
1196 }
1197<IncludeDoc,SnippetDoc>. { // invalid character
1198 copyToOutput(yyscanner,yytext,yyleng);
1199 BEGIN(yyextra->includeCtx);
1200 }
1201<CComment,ReadLine,IncludeFile>[\\@]"cond"/[^a-z_A-Z0-9] { // conditional section
1202 yyextra->condCtx = YY_START;
1203 BEGIN(CondLine);
1204 }
1205<CComment,ReadLine,IncludeFile>[\\@]"endcond"/[^a-z_A-Z0-9] { // end of conditional section
1206 bool oldSkip=yyextra->skip;
1207 endCondSection(yyscanner);
1208 if (YY_START==CComment && oldSkip && !yyextra->skip)
1209 {
1210 //printf("** Adding start of comment!\n");
1211 if (yyextra->lang!=SrcLangExt::Python &&
1212 yyextra->lang!=SrcLangExt::VHDL &&
1213 yyextra->lang!=SrcLangExt::Markdown &&
1214 yyextra->lang!=SrcLangExt::Fortran)
1215 {
1216 yyextra->outBuf+='/';
1217 yyextra->outBuf+='*';
1218 yyextra->col+=2;
1219 if (yyextra->specialComment)
1220 {
1221 yyextra->outBuf+='*';
1222 yyextra->col++;
1223 }
1224 }
1225 }
1226 }
1227<CondLine>[!()&| \ta-z_A-Z0-9.\-]+ {
1228 handleCondSectionId(yyscanner,yytext);
1229 }
1230<CComment,ReadLine,IncludeFile>[\\@]"cond"{WSopt}/\n {
1231 yyextra->condCtx=YY_START;
1232 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
1233 }
1234<CondLine>\n |
1235<CondLine>. { // forgot section id?
1236 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
1237 if (*yytext=='\n') { copyToOutput(yyscanner,"\n");}
1238 }
1239<CComment,ReadLine,IncludeFile,Verbatim,VerbatimCode>[\\@][a-z_A-Z][a-z_A-Z0-9-]* { // expand alias without arguments
1240 replaceAliases(yyscanner,yytext,YY_START==ReadLine && yyextra->readLineCtx==SComment);
1241 }
1242<CComment,ReadLine,IncludeFile,Verbatim,VerbatimCode>{B}?{CMD}"ilinebr"{B}[\\@]"ialias{" { // expand alias with arguments
1243 yyextra->lastBlockContext=YY_START;
1244 yyextra->blockCount=1;
1245 int extraSpace = (yytext[0]==' '? 1:0);
1246 yyextra->aliasString=yytext+9+extraSpace;
1247 yyextra->aliasCmd=yytext+9+extraSpace;
1248 yyextra->lastEscaped=0;
1249 BEGIN( ReadAliasArgs );
1250 }
1251<CComment,ReadLine,IncludeFile,Verbatim,VerbatimCode>[\\@][a-z_A-Z][a-z_A-Z0-9-]*"{" { // expand alias with arguments
1252 yyextra->lastBlockContext=YY_START;
1253 yyextra->blockCount=1;
1254 yyextra->aliasString=yytext;
1255 yyextra->aliasCmd=yytext;
1256 yyextra->lastEscaped=0;
1257 BEGIN( ReadAliasArgs );
1258 }
1259<ReadAliasArgs>^[ \t]*"*" { // skip leading *
1260 }
1261<ReadAliasArgs>^[ \t]*{CPPC}[/!]/[^\n]* { // skip leading special comments (see bug 618079)
1262 }
1263<ReadAliasArgs>[^{}\n\\\*]+ {
1264 yyextra->aliasString+=yytext;
1265 yyextra->lastEscaped=FALSE;
1266 }
1267<ReadAliasArgs>"\\" {
1268 if (yyextra->lastEscaped) yyextra->lastEscaped=FALSE;
1269 else yyextra->lastEscaped=TRUE;
1270 yyextra->aliasString+=yytext;
1271 }
1272<ReadAliasArgs>[\\@]("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}"|"f)") { /* end of verbatim block */
1273 yyextra->aliasString+=yytext;
1274 if (yyextra->inVerbatim && &yytext[1]==yyextra->blockName)
1275 // For verbatim sections we do not support matching end block markers inside
1276 // alias arguments. Instead this will end the verbatim block.
1277 // This is needed to support an alias definition
1278 // like startalign=" \latexonly\noalign{\endlatexonly" were otherwise
1279 // the scanner would try to find a matching closing brace for noalign and then
1280 // skip over the \endlatexonly command.
1281 {
1282 copyToOutput(yyscanner,yyextra->aliasString.view());
1283 yyextra->inVerbatim=false;
1284 BEGIN(yyextra->lastCommentContext);
1285 }
1286 }
1287<ReadAliasArgs>\n {
1288 yyextra->aliasString+=yytext;
1289 yyextra->lastEscaped=FALSE;
1290 if (yyextra->inVerbatim) // for verbatim sections we do not support multi-line
1291 // alias arguments.
1292 {
1293 copyToOutput(yyscanner,yyextra->aliasString.view());
1294 BEGIN( yyextra->lastBlockContext );
1295 }
1296 }
1297<ReadAliasArgs>"{" {
1298 yyextra->aliasString+=yytext;
1299 if (!yyextra->lastEscaped) yyextra->blockCount++;
1300 yyextra->lastEscaped=FALSE;
1301 }
1302<ReadAliasArgs>"}" {
1303 yyextra->aliasString+=yytext;
1304 if (!yyextra->lastEscaped) yyextra->blockCount--;
1305 if (yyextra->blockCount==0)
1306 {
1307 replaceAliases(yyscanner,yyextra->aliasString.view(),
1308 yyextra->lastBlockContext==ReadLine && yyextra->readLineCtx==SComment);
1309 BEGIN( yyextra->lastBlockContext );
1310 }
1311 yyextra->lastEscaped=FALSE;
1312 }
1313<ReadAliasArgs>. {
1314 yyextra->aliasString+=yytext;
1315 yyextra->lastEscaped=FALSE;
1316 }
1317<CopyLine>. {
1318 copyToOutput(yyscanner,yytext,yyleng);
1319 }
1320<CopyLine>\n {
1321 copyToOutput(yyscanner,yytext,yyleng);
1322 yyextra->insertCppCommentMarker=false;
1323 BEGIN(yyextra->readLineCtx);
1324 }
1325<ReadLine>``` {
1326 copyToOutput(yyscanner,yytext,yyleng);
1327 }
1328<ReadLine>`[^`]+` {
1329 copyToOutput(yyscanner,yytext,yyleng);
1330 }
1331<ReadLine>{CMD}{CMD} |
1332<ReadLine>. {
1333 copyToOutput(yyscanner,yytext,yyleng);
1334 }
1335<IncludeFile>. {
1336 copyToOutput(yyscanner,yytext,yyleng);
1337 }
1338<IncludeFile>\n {
1339 copyToOutput(yyscanner,yytext,yyleng);
1340 insertCommentStart(yyscanner);
1341 }
1342<*>. {
1343 copyToOutput(yyscanner,yytext,yyleng);
1344 }
1345<<EOF>> {
1346 if (YY_START == ReadAliasArgs)
1347 {
1348 warn(yyextra->fileName,yyextra->lineNr,
1349 "Reached end of file while still searching closing '}}' of an alias argument (probable start: '{}')",
1350 yyextra->aliasCmd);
1351 }
1352 if (yyextra->includeStack.empty())
1353 {
1354 yyextra->insertCppCommentMarker=false;
1355 yyterminate();
1356 }
1357 else // switch back to parent file
1358 {
1359 std::unique_ptr<commentcnv_FileState> &fs = yyextra->includeStack.back();
1360 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
1361 yy_switch_to_buffer(fs->bufState, yyscanner);
1362 yy_delete_buffer(oldBuf, yyscanner);
1363 BEGIN(fs->oldState);
1364 yyextra->fileName = fs->oldFileName;
1365 yyextra->lineNr = fs->oldLineNr;
1366 yyextra->inBuf = fs->oldFileBuf;
1367 yyextra->inBufPos = fs->oldFileBufPos;
1368 yyextra->includeCtx = fs->oldIncludeCtx;
1369 QCString lineStr= " \\ifile \""+yyextra->fileName+"\" \\iline "+QCString().setNum(yyextra->lineNr)+" ";
1370 if (fs->oldRaiseLvl!=yyextra->raiseLevel)
1371 {
1372 lineStr+="\\iraise " + std::to_string(fs->oldRaiseLvl)+ " ";
1373 }
1374 if (fs->oldRaiseLbl!=yyextra->raiseLabel)
1375 {
1376 lineStr+="\\iprefix \"" + fs->oldRaiseLbl + "\" ";
1377 }
1378 lineStr+="\\ilinebr ";
1379 yyextra->raiseLevel = fs->oldRaiseLvl;
1380 yyextra->raiseLabel = fs->oldRaiseLbl;
1381 copyToOutput(yyscanner,lineStr.view());
1382 yyextra->includeStack.pop_back();
1383 //printf("<<EOF>> switch back to %s line %d inbufPos=%d outbufPos=%d\n",
1384 // qPrint(yyextra->fileName),yyextra->lineNr,yyextra->inBufPos,yyextra->outBuf.curPos());
1385 }
1386 }
QCString & setNum(short n)
Definition qcstring.h:444
std::string_view view() const
Definition qcstring.h:161
#define yyterminate()
1387 /*
1388<*>\n { fprintf(stderr,"Lex scanner %s (%s) default rule newline for state %s.\n", __FILE__, qPrint(yyextra->fileName),stateToString(YY_START));}
1389 */
1390%%
1391
1392static bool parseIncludeOptions(yyscan_t yyscanner,std::string_view s)
1393{
1394 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1395
1396 //printf("parseIncludeOptions=%s\n",qPrint(QCString(s)));
1397 size_t optIdxStart = s.find('{');
1398 size_t optIdxEnd = optIdxStart!=std::string::npos ? s.find("}",optIdxStart+1) : std::string::npos;
1399 std::string cmdName;
1400 StringVector optList;
1401 if (optIdxStart == std::string::npos) // no options
1402 {
1403 cmdName = stripWhiteSpace(s.substr(1)); // to remove {CMD}
1404 }
1405 else // options present
1406 {
1407 cmdName = stripWhiteSpace(s.substr(1,optIdxStart-1)); // to remove {CMD}
1408 optList = split(std::string{s.substr(optIdxStart+1,optIdxEnd-optIdxStart-1)},",");
1409 }
1410 bool isDoc = cmdName=="includedoc" || cmdName=="snippetdoc";
1411 for (const auto &opt : optList)
1412 {
1413 if (stripWhiteSpace(opt)==std::string_view{"doc"})
1414 {
1415 isDoc=true;
1416 break;
1417 }
1418 }
1419
1420 if (isDoc)
1421 {
1422 for (const auto &opt : optList)
1423 {
1424 std::string_view locOpt = stripWhiteSpace(opt);
1425 size_t posEqual = locOpt.find('=');
1426 std::string_view option = posEqual!=std::string::npos ? stripWhiteSpace(locOpt.substr(0,posEqual)) : locOpt;
1427 std::string_view value = posEqual!=std::string::npos ? stripWhiteSpace(locOpt.substr(posEqual+1)) : std::string_view();
1428
1429 if (option==std::string_view{"doc"} && value.empty())
1430 {
1431 }
1432 else if (option==std::string_view{"raise"} && !value.empty())
1433 {
1434 yyextra->raiseIncrement = atoi(value.data());
1435 if (yyextra->raiseLevel+yyextra->raiseIncrement>=SectionType::MaxLevel) // check range
1436 {
1437 warn(yyextra->fileName,yyextra->lineNr,"Raising section level from {} to {}, exceeds allowed range [0-{}], adjusting",
1438 yyextra->raiseLevel,yyextra->raiseLevel+yyextra->raiseIncrement,SectionType::MaxLevel-1);
1439 yyextra->raiseIncrement = std::max(0,SectionType::MaxLevel-1-yyextra->raiseLevel);
1440 }
1441 }
1442 else if (option==std::string_view{"prefix"} && !value.empty())
1443 {
1444 yyextra->raisePrefix = value;
1445 }
1446 else
1447 {
1448 warn(yyextra->fileName,yyextra->lineNr,"Unsupported option '{}' for {} command",option, cmdName);
1449 }
1450 }
1451 }
1452
1453 return isDoc;
1454}
1455
1456
1457static void replaceCommentMarker(yyscan_t yyscanner,std::string_view s)
1458{
1459 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1460 if (s.empty()) return;
1461 size_t p = 0;
1462 size_t len = s.length();
1463 char c = 0;
1464 // copy leading blanks
1465 while (p<len && (c=s[p]) && (c==' ' || c=='\t' || c=='\n'))
1466 {
1467 yyextra->outBuf+=c;
1468 if (c=='\n') { yyextra->lineNr++; yyextra->col=0; } else { yyextra->col++; }
1469 p++;
1470 }
1471 // replace start of comment marker by blanks and the last character by a *
1472 int blanks=0;
1473 while (p<len && (c=s[p]) && (c=='/' || c=='!' || c=='#'))
1474 {
1475 blanks++;
1476 p++;
1477 if (p<len && s[p]=='<') // comment-after-item marker
1478 {
1479 blanks++;
1480 p++;
1481 }
1482 if (c=='!') // end after first !
1483 {
1484 break;
1485 }
1486 }
1487 if (blanks>0)
1488 {
1489 while (blanks>2)
1490 {
1491 yyextra->outBuf+=' ';
1492 yyextra->col++;
1493 blanks--;
1494 }
1495 if (blanks>1) { yyextra->outBuf+='*'; yyextra->col++; }
1496 yyextra->outBuf+=' ';
1497 yyextra->col++;
1498 }
1499 // copy comment line to output
1500 yyextra->outBuf+=s.substr(p);
1501 yyextra->col+=s.substr(p).length();
1502}
1503
1504static inline int computeIndent(const char *s)
1505{
1506 int col=0;
1507 int tabSize=Config_getInt(TAB_SIZE);
1508 const char *p=s;
1509 char c = 0;
1510 while ((c=*p++))
1511 {
1512 if (c==' ') col++;
1513 else if (c=='\t') col+=tabSize-(col%tabSize);
1514 else break;
1515 }
1516 return col;
1517}
1518
1519static inline void copyToOutput(yyscan_t yyscanner,std::string_view s)
1520{
1521 int tabSize=Config_getInt(TAB_SIZE);
1522 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1523 size_t len = s.length();
1524 if (yyextra->skip) // only add newlines.
1525 {
1526 for (size_t i=0;i<len;i++)
1527 {
1528 switch(s[i])
1529 {
1530 case '\n':
1531 yyextra->outBuf+='\n';
1532 yyextra->lineNr++;
1533 yyextra->col=0;
1534 break;
1535 case '\t':
1536 yyextra->col+=tabSize-(yyextra->col%tabSize);
1537 break;
1538 default:
1539 yyextra->col++;
1540 break;
1541 }
1542 }
1543 }
1544 else if (len>0)
1545 {
1546 yyextra->outBuf+=s;
1547 for (size_t i=0;i<len;i++)
1548 {
1549 switch (s[i])
1550 {
1551 case '\n': yyextra->col=0;
1552 //fprintf(stderr,"---> copy %d\n",g_lineNr);
1553 yyextra->lineNr++; break;
1554 case '\t': yyextra->col+=tabSize-(yyextra->col%tabSize); break;
1555 default: yyextra->col++; break;
1556 }
1557 }
1558 }
1559}
1560
1561static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len)
1562{
1563 copyToOutput(yyscanner,std::string_view{s,(size_t)len});
1564}
1565
1566static void clearCommentStack(yyscan_t yyscanner)
1567{
1568 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1569 while (!yyextra->commentStack.empty()) yyextra->commentStack.pop();
1570}
1571
1572static void startCondSection(yyscan_t yyscanner,const QCString &sectId)
1573{
1574 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1575 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1576 CondParser prs;
1577 bool expResult = prs.parse(yyextra->fileName,yyextra->lineNr,sectId);
1578 yyextra->condStack.emplace(yyextra->lineNr,sectId,yyextra->skip);
1579 if (!expResult) // not enabled
1580 {
1581 yyextra->skip=TRUE;
1582 }
1583}
1584
1585static void endCondSection(yyscan_t yyscanner)
1586{
1587 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1588 if (yyextra->condStack.empty())
1589 {
1590 warn(yyextra->fileName,yyextra->lineNr,"Found \\endcond command without matching \\cond");
1591 yyextra->skip=FALSE;
1592 }
1593 else
1594 {
1595 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
1596 yyextra->skip=ctx.skip;
1597 yyextra->condStack.pop();
1598 }
1599 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1600}
1601
1602static void handleCondSectionId(yyscan_t yyscanner,const char *expression)
1603{
1604 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1605 bool oldSkip=yyextra->skip;
1606 startCondSection(yyscanner,QCString(expression));
1607 if ((yyextra->condCtx==CComment || yyextra->readLineCtx==SComment) &&
1608 !oldSkip && yyextra->skip)
1609 {
1610 if (yyextra->lang!=SrcLangExt::Python &&
1611 yyextra->lang!=SrcLangExt::VHDL &&
1612 yyextra->lang!=SrcLangExt::Markdown &&
1613 yyextra->lang!=SrcLangExt::Fortran)
1614 {
1615 yyextra->outBuf+='*';
1616 yyextra->outBuf+='/';
1617 yyextra->col+=2;
1618 }
1619 }
1620 if (yyextra->readLineCtx==SComment)
1621 {
1622 BEGIN(SComment);
1623 }
1624 else
1625 {
1626 BEGIN(yyextra->condCtx);
1627 }
1628}
1629
1630/** Returns the section of text, in between a pair of markers.
1631 * Full lines are returned, excluding the lines on which the markers appear.
1632 * \sa routine lineBlock
1633 */
1634static QCString extractBlock(const QCString &text,const QCString &marker,int &blockPos)
1635{
1636 QCString result;
1637 int p=0,i=-1;
1638 bool found=FALSE;
1639
1640 // find the character positions of the markers
1641 int m1 = text.find(marker);
1642 if (m1==-1) return result;
1643 int m2 = text.find(marker,m1+static_cast<int>(marker.length()));
1644 if (m2==-1) return result;
1645
1646 // find start and end line positions for the markers
1647 int l1=-1,l2=-1;
1648 while (!found && (i=text.find('\n',p))!=-1)
1649 {
1650 found = (p<=m1 && m1<i); // found the line with the start marker
1651 p=i+1;
1652 }
1653 l1=p;
1654 blockPos=p;
1655 int lp=i;
1656 if (found)
1657 {
1658 while ((i=text.find('\n',p))!=-1)
1659 {
1660 if (p<=m2 && m2<i) // found the line with the end marker
1661 {
1662 l2=p;
1663 break;
1664 }
1665 p=i+1;
1666 lp=i;
1667 }
1668 }
1669 if (l2==-1) // marker at last line without newline (see bug706874)
1670 {
1671 l2=lp;
1672 }
1673 return l2>l1 ? text.mid(l1,l2-l1) : QCString();
1674}
1675
1676static void insertCommentStart(yyscan_t yyscanner)
1677{
1678 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1679 int startCol=yyextra->blockHeadCol;
1680 int contentCol=yyextra->insertCommentCol;
1681 int markerSpace=contentCol-startCol;
1682 //printf("insertCommentStart startCol=%d contentCol=%d mlBrief=%d insertCppCommentMarker=%d\n",
1683 // yyextra->blockHeadCol,yyextra->insertCommentCol,yyextra->mlBrief,yyextra->insertCppCommentMarker);
1684 std::string marker;
1685 if (yyextra->lang==SrcLangExt::Python) // need to insert # or space
1686 {
1687 if (yyextra->pythonDocString) // """! style comment
1688 {
1689 marker=" ";
1690 }
1691 else
1692 {
1693 marker="# ";
1694 }
1695 }
1696 else if (yyextra->lang==SrcLangExt::Fortran) // need to insert !!
1697 {
1698 marker="!! ";
1699 }
1700 else if (yyextra->lang==SrcLangExt::Markdown)
1701 {
1702 marker=" ";
1703 }
1704 else if (yyextra->insertCppCommentMarker) // need to insert ///
1705 {
1706 marker="/// ";
1707 if (startCol>0)
1708 {
1709 // insert `///` instead of '* '
1710 startCol--;
1711 markerSpace++;
1712 }
1713 }
1714 else // need to insert *
1715 {
1716 marker="* ";
1717 }
1718 int i=0;
1719 for (;i<startCol;i++)
1720 {
1721 copyToOutput(yyscanner," ");
1722 }
1723 if (static_cast<int>(marker.length())<=markerSpace && !yyextra->firstIncludeLine)
1724 {
1725 copyToOutput(yyscanner,marker);
1726 i+=marker.length();
1727 }
1728 for (;i<contentCol;i++)
1729 {
1730 copyToOutput(yyscanner," ");
1731 }
1732 yyextra->firstIncludeLine = false;
1733}
1734
1735static bool readIncludeFile(yyscan_t yyscanner,const QCString &inc,const QCString &blockId)
1736{
1737 //printf("readIncludeFile(inc=%s,blockId=%s)\n",qPrint(inc),qPrint(blockId));
1738 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1739 bool ambig = false;
1740 QCString absFileName = findFilePath(inc,ambig);
1741 FileInfo fi(absFileName.str());
1742 if (!absFileName.isEmpty() && fi.exists() && fi.isFile())
1743 {
1744 if (ambig)
1745 {
1746 warn_doc_error(yyextra->fileName,yyextra->lineNr,"included file name '{}' is ambiguous"
1747 "Possible candidates:\n{}",inc, showFileDefMatches(Doxygen::exampleNameLinkedMap,inc));
1748 }
1749 bool alreadyProcessed = std::any_of(
1750 yyextra->includeStack.begin(),
1751 yyextra->includeStack.end(),
1752 [&absFileName,&blockId](const auto &lfs)
1753 { return lfs->fileName==absFileName && lfs->blockId==blockId; }
1754 );
1755
1756 if (alreadyProcessed)
1757 {
1758 if (!blockId.isEmpty())
1759 {
1760 warn_doc_error(yyextra->fileName,yyextra->lineNr,"recursive usage of '\\snippet{{doc}}' block with name '{}' and file name '{}', skipping",
1761 blockId,absFileName);
1762 }
1763 else
1764 {
1765 warn_doc_error(yyextra->fileName,yyextra->lineNr,"recursive usage of '\\include{{doc}}' with file name '{}', skipping", absFileName);
1766 }
1767 return false;
1768 }
1769
1770 auto fs = std::make_unique<commentcnv_FileState>();
1771 if (!readInputFile(absFileName,fs->fileBuf,false))
1772 {
1773 warn_doc_error(yyextra->fileName,yyextra->lineNr,"\\{}{{doc}} file '{}' could not be read",blockId.isEmpty()?"include":"snippet",absFileName);
1774 fs.reset();
1775 return false;
1776 }
1777 int lineNr=1;
1778 if (!blockId.isEmpty())
1779 {
1780 QCString incText { fs->fileBuf };
1781 int count = incText.contains(blockId.data());
1782 if (count!=2)
1783 {
1784 warn_doc_error(yyextra->fileName,yyextra->lineNr,"block marked with {} for \\snippet{{doc}} should appear twice in file {}, found it {:d} times, skipping",
1785 blockId,absFileName,count);
1786 return false;
1787 }
1788 lineNr = lineBlock(incText, blockId);
1789 int blockPos = 0;
1790 incText = extractBlock(incText, blockId, blockPos);
1791 fs->fileBuf.clear();
1792 if (!incText.isEmpty())
1793 {
1794 fs->fileBuf.append(incText.str());
1795 }
1796 }
1797 int oldRaiseLevel = yyextra->raiseLevel;
1798 QCString oldRaiseLabel = yyextra->raiseLabel;
1799 yyextra->raiseLevel+=yyextra->raiseIncrement;
1800 yyextra->raiseLabel+=yyextra->raisePrefix;
1801 QCString lineStr=" \\ifile \""+absFileName+"\" \\iline " + std::to_string(lineNr)+" ";
1802 if (yyextra->raiseLevel>0)
1803 {
1804 lineStr+="\\iraise " + std::to_string(yyextra->raiseLevel)+" ";
1805 }
1806 if (!yyextra->raiseLabel.isEmpty())
1807 {
1808 lineStr+="\\iprefix \"" + yyextra->raiseLabel + "\" ";
1809 }
1810 lineStr+="\\ilinebr ";
1811 copyToOutput(yyscanner,lineStr.view());
1812
1813 fs->fileName = absFileName;
1814 fs->bufState = YY_CURRENT_BUFFER;
1815 fs->oldLineNr = yyextra->lineNr;
1816 fs->oldFileName = yyextra->fileName;
1817 fs->oldState = yyextra->includeCtx;
1818 fs->oldFileBuf = yyextra->inBuf;
1819 fs->oldFileBufPos = yyextra->inBufPos;
1820 fs->oldIncludeCtx = yyextra->includeCtx;
1821 fs->oldRaiseLvl = oldRaiseLevel;
1822 fs->oldRaiseLbl = oldRaiseLabel;
1823 fs->blockId = blockId;
1824 yy_switch_to_buffer(yy_create_buffer(nullptr, YY_BUF_SIZE, yyscanner),yyscanner);
1825 yyextra->fileName = absFileName;
1826 yyextra->lineNr = lineNr;
1827 yyextra->inBuf = &fs->fileBuf;
1828 yyextra->inBufPos = 0;
1829 yyextra->includeStack.push_back(std::move(fs));
1830 insertCommentStart(yyscanner);
1831 //printf("switched to %s\n",qPrint(fileName));
1832 }
1833 else
1834 {
1835 warn_doc_error(yyextra->fileName,yyextra->lineNr,"\\{}{{doc}} file '{}' not found",blockId.isEmpty()?"include":"snippet",inc);
1836 return false;
1837 }
1838 return true;
1839}
1840
1841/** copies string \a s with length \a len to the output, while
1842 * replacing any alias commands found in the string.
1843 */
1844static void replaceAliases(yyscan_t yyscanner,std::string_view s,bool replaceComment)
1845{
1846 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1847 if (s.empty()) return;
1848 size_t pos = s.find('{');
1849 std::string cmd { s.substr(1, pos!=std::string::npos ? pos-1 : s.length()-1) };
1850 auto &expAlias = yyextra->expandedAliases;
1851 if (std::find(expAlias.begin(),expAlias.end(),cmd)!=std::end(expAlias))
1852 {
1853 copyToOutput(yyscanner,s);
1854 return; // prevent recursive expansion
1855 }
1856 else if (cmd=="ialias")
1857 {
1858 if (s.length()>cmd.length()+3) // \cmd{value}
1859 {
1860 std::string value { s.substr(cmd.length()+2,s.length()-cmd.length()-3) };
1861 //printf("removing value '%s'\n",qPrint(value));
1862 expAlias.erase(std::remove(expAlias.begin(),expAlias.end(),value),expAlias.end());
1863 }
1864 return;
1865 }
1866 std::string result = resolveAliasCmd(s);
1867 if (yyextra->inVerbatim) // inside verbatim blocks (like @code...@endcode) only expand aliases if
1868 // their expansion contains the matching end block marker.
1869 {
1870 std::string blk = yyextra->blockName.str();
1871 assert(!blk.empty());
1872 bool isNamedCommand=isId(blk[0]); // true for e.g. @endcode, false for e.g. ~~~
1873 size_t i=0,p=0;
1874 bool found=false;
1875 while ((i=result.find(blk,p))!=std::string::npos && !found) // for each match of blk in result
1876 {
1877 found = !isNamedCommand || // e.g. '~~~' or '-->'
1878 (i>0 && (result[i-1]=='\\' || result[i-1]=='@') && !isId(result[i+blk.length()])); // e.g. '@endcode' but not ~endcode or @endcodex
1879 p = i+yyextra->blockName.length();
1880 }
1881 //printf("blk=%s result=%s found=%d\n",qPrint(blk),qPrint(result),found);
1882 if (!found) // treat alias as part of the verbatim block
1883 {
1884 copyToOutput(yyscanner,s);
1885 return;
1886 }
1887 }
1888 //printf("replaceAliases(%s)->'%s' replaceComment=%d\n",qPrint(s),qPrint(result),replaceComment);
1889 if (result!=s)
1890 {
1891 if (replaceComment) // In case we are replacing a multiline /// comment by a C style comment
1892 // and we have new lines in the alias argument, we need to place back a /// for each new line
1893 // to prevent breaking the multiline comment into multiple C style comments
1894 {
1895 result = substituteStringView(result,"\n","\n///");
1896 }
1897 expAlias.push_back(cmd);
1898 // add a ialias command to allow expansion of cmd again
1899 result += " \\ilinebr \\ialias{";
1900 result += cmd;
1901 result += "}";
1902 for (int i=(int)result.length()-1; i>=0; i--)
1903 {
1904 unput(result[i]);
1905 }
1906 }
1907 else
1908 {
1909 copyToOutput(yyscanner,result);
1910 }
1911}
1912
1913
1914static int yyread(yyscan_t yyscanner,char *buf,int max_size)
1915{
1916 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1917 int bytesInBuf = static_cast<int>(yyextra->inBuf->size())-yyextra->inBufPos;
1918 int bytesToCopy = std::min(max_size,bytesInBuf);
1919 memcpy(buf,yyextra->inBuf->data()+yyextra->inBufPos,bytesToCopy);
1920 yyextra->inBufPos+=bytesToCopy;
1921 return bytesToCopy;
1922}
1923
1924static void replaceComment(yyscan_t yyscanner,int offset)
1925{
1926 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1927 if (yyextra->mlBrief || yyextra->skip)
1928 {
1929 copyToOutput(yyscanner,yytext,yyleng);
1930 }
1931 else
1932 {
1933 int i=computeIndent(&yytext[offset]);
1934 //printf("i=%d blockHeadCol=%d\n",i,yyextra->blockHeadCol);
1935 if (i==yyextra->blockHeadCol || i+1==yyextra->blockHeadCol)
1936 {
1937 replaceCommentMarker(yyscanner,std::string_view(yytext,yyleng));
1938 }
1939 else
1940 {
1941 copyToOutput(yyscanner," */");
1942 for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
1943 yyextra->inSpecialComment=FALSE;
1944 BEGIN(Scan);
1945 }
1946 }
1947}
1948
1949/*! This function does three things:
1950 * -# It converts multi-line C++ style comment blocks (that are aligned)
1951 * to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
1952 * -# It replaces aliases with their definition (see ALIASES)
1953 * -# It handles conditional sections (cond...endcond blocks)
1954 */
1955void convertCppComments(const std::string &inBuf,std::string &outBuf,const std::string &fn)
1956{
1957 QCString fileName { fn };
1958 yyscan_t yyscanner;
1959 commentcnvYY_state extra(&inBuf,outBuf);
1960 commentcnvYYlex_init_extra(&extra,&yyscanner);
1961#ifdef FLEX_DEBUG
1962 commentcnvYYset_debug(Debug::isFlagSet(Debug::Lex_commentcnv)?1:0,yyscanner);
1963#endif
1964 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1965 //printf("convertCppComments(%s)\n",qPrint(fileName));
1966 yyextra->inBufPos = 0;
1967 yyextra->col = 0;
1968 yyextra->mlBrief = Config_getBool(MULTILINE_CPP_IS_BRIEF);
1969 yyextra->skip = FALSE;
1970 yyextra->fileName = fileName;
1971 yyextra->lang = getLanguageFromFileName(fileName);
1972 yyextra->pythonDocString = FALSE;
1973 yyextra->lineNr = 1;
1974 yyextra->raiseLevel = 0;
1975 yyextra->raiseLabel = "";
1976 yyextra->raiseIncrement = 0;
1977 yyextra->raisePrefix = "";
1978 yyextra->insertCppCommentMarker=false;
1979 yyextra->expandedAliases.clear();
1980 while (!yyextra->condStack.empty()) yyextra->condStack.pop();
1981 clearCommentStack(yyscanner);
1982 yyextra->vhdl = FALSE;
1983
1984 DebugLex debugLex(Debug::Lex_commentcnv,__FILE__, qPrint(fileName));
1985 yyextra->isFixedForm = FALSE;
1986 if (yyextra->lang==SrcLangExt::Fortran)
1987 {
1989 yyextra->isFixedForm = recognizeFixedForm(QCString(inBuf),fmt);
1990 }
1991
1992 if (yyextra->lang==SrcLangExt::Markdown)
1993 {
1994 yyextra->nestingCount=0;
1995 BEGIN(CComment);
1996 yyextra->commentStack.push(yyextra->lineNr);
1997 }
1998 else
1999 {
2000 BEGIN(Scan);
2001 }
2002 yylex(yyscanner);
2003 while (!yyextra->condStack.empty())
2004 {
2005 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
2006 QCString sectionInfo(" ");
2007 if (ctx.sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",ctx.sectionId.stripWhiteSpace().data());
2008 warn(yyextra->fileName,ctx.lineNr,"Conditional section{}does not have "
2009 "a corresponding \\endcond command within this file.",sectionInfo.data());
2010 yyextra->condStack.pop();
2011 }
2012 if (yyextra->nestingCount>0 && yyextra->lang!=SrcLangExt::Markdown && yyextra->lang!=SrcLangExt::Fortran)
2013 {
2014 QCString lines;
2015 bool first = true;
2016 while (!yyextra->commentStack.empty())
2017 {
2018 int lineNr = yyextra->commentStack.top();
2019 if (!first) lines += ", ";
2020 lines += QCString().setNum(lineNr);
2021 first = false;
2022 yyextra->commentStack.pop();
2023 }
2024 warn(yyextra->fileName,yyextra->lineNr,"Reached end of file while still inside a (nested) comment. "
2025 "Nesting level {} (possible line reference(s): {})",yyextra->nestingCount,lines);
2026 }
2027 yyextra->nestingCount = 0;
2029 {
2030 Debug::print(Debug::CommentCnv,0,"-----------\nCommentCnv: {}\n"
2031 "output=[\n{}]\n-----------\n",fileName,yyextra->outBuf
2032 );
2033 }
2034 commentcnvYYlex_destroy(yyscanner);
2035}
2036
2037
2038//----------------------------------------------------------------------------
2039
2040#include "commentcnv.l.h"
std::string resolveAliasCmd(std::string_view aliasCmd)
Definition aliases.cpp:504
Copyright (C) 1997-2015 by Dimitri van Heesch.
Definition condparser.h:28
bool parse(const QCString &fileName, int lineNr, const QCString &expr)
Copyright (C) 1997-2015 by Dimitri van Heesch.
@ Lex_commentcnv
Definition debug.h:53
@ CommentCnv
Definition debug.h:31
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:132
static void print(DebugMask mask, int prio, fmt::format_string< Args... > fmt, Args &&... args)
Definition debug.h:76
static FileNameLinkedMap * exampleNameLinkedMap
Definition doxygen.h:103
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
bool exists() const
Definition fileinfo.cpp:30
bool isFile() const
Definition fileinfo.cpp:63
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
const std::string & str() const
Definition qcstring.h:537
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:159
int contains(char c, bool cs=TRUE) const
Definition qcstring.cpp:143
static constexpr int MaxLevel
Definition section.h:39
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
Definition code.l:3989
void convertCppComments(const std::string &inBuf, std::string &outBuf, const std::string &fn)
Converts the comments in a file.
static QCString extractBlock(const QCString &text, const QCString &marker, int &blockPos)
Returns the section of text, in between a pair of markers.
#define YY_BUF_SIZE
Definition commentcnv.l:19
#define Config_getInt(name)
Definition config.h:34
int yylex(void)
std::vector< std::string > StringVector
Definition containers.h:33
#define warn_doc_error(file, line, fmt,...)
Definition message.h:112
Definition message.h:144
const char * qPrint(const char *s)
Definition qcstring.h:672
std::string substituteStringView(std::string_view s, std::string_view toReplace, std::string_view replaceWith)
Returns a new string where occurrences of substring toReplace in string s are replaced by string repl...
Definition stringutil.h:50
FortranFormat
Definition types.h:572
QCString findFilePath(const QCString &file, bool &ambig)
Definition util.cpp:3498
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5721
int lineBlock(const QCString &text, const QCString &marker)
Returns the line number of the line following the line with the marker.
Definition util.cpp:6349
bool readInputFile(const QCString &fileName, std::string &contents, bool filter, bool isSourceCode)
read a file name fileName and optionally filter and transcode it
Definition util.cpp:6013
bool recognizeFixedForm(const QCString &contents, FortranFormat format)
Definition util.cpp:6820
QCString showFileDefMatches(const FileNameLinkedMap *fnMap, const QCString &n)
Definition util.cpp:3541
bool found
Definition util.cpp:984
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:7095
FortranFormat convertFileNameFortranParserCode(QCString fn)
Definition util.cpp:6873
bool isId(int c)
Definition util.h:208