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