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>"'" {
772 copyToOutput(yyscanner,yytext,yyleng);
773 if (yyextra->blockName=="`") // support for `text'
774 {
775 yyextra->inVerbatim=false;
776 BEGIN(yyextra->lastCommentContext);
777 }
778 }
779<VerbatimCode>"`"{1,2} {
780 copyToOutput(yyscanner,yytext,yyleng);
781 if (yytext==yyextra->blockName)
782 {
783 yyextra->inVerbatim=false;
784 BEGIN(yyextra->lastCommentContext);
785 }
786 }
787<VerbatimCode>{CMD}("enddot"|"endcode"|"endmsc"|"enduml")/("{")? { // end of verbatim block
788 copyToOutput(yyscanner,yytext,yyleng);
789 if (&yytext[1]==yyextra->blockName)
790 {
791 yyextra->inVerbatim=false;
792 BEGIN(yyextra->lastCommentContext);
793 }
794 }
795<VerbatimCode>^[ \t]*{CPPC}[\!\/]? { /* skip leading comments */
796 if (!yyextra->inSpecialComment || yyextra->mlBrief)
797 {
798 copyToOutput(yyscanner,yytext,yyleng);
799 }
800 else
801 {
802 int l=0;
803 while (yytext[l]==' ' || yytext[l]=='\t')
804 {
805 l++;
806 }
807 copyToOutput(yyscanner,yytext,l);
808 if (yyleng-l==3) // ends with //! or ///
809 {
810 copyToOutput(yyscanner," * ");
811 }
812 else // ends with //
813 {
814 copyToOutput(yyscanner,"//");
815 }
816 }
817 }
818<Verbatim,VerbatimCode>[^`'~@\/\-\\\n{}]* { /* any character not a backslash or new line or } */
819 copyToOutput(yyscanner,yytext,yyleng);
820 }
821<Verbatim,VerbatimCode>[^`'~@\/\-\\\n{}]+/\n { /* premature end of comment block */
822 if (yyextra->lastCommentContext==ReadLine)
823 {
824 yyextra->inVerbatim=false;
825 BEGIN(yyextra->lastCommentContext);
826 }
827 copyToOutput(yyscanner,yytext,yyleng);
828 }
829<Verbatim,VerbatimCode>\n { /* new line in verbatim block */
830 copyToOutput(yyscanner,yytext,yyleng);
831 if (yyextra->lastCommentContext == IncludeFile)
832 {
833 insertCommentStart(yyscanner);
834 }
835 }
836<Verbatim>^[ \t]*{CPPC}[/!] {
837 if (yyextra->blockName=="enddot" || yyextra->blockName=="endmsc" || yyextra->blockName=="enduml" || yyextra->blockName.at(0)=='f')
838 {
839 // see bug 487871, strip /// from dot images and formulas.
840 int l=0;
841 while (yytext[l]==' ' || yytext[l]=='\t')
842 {
843 l++;
844 }
845 copyToOutput(yyscanner,yytext,l);
846 copyToOutput(yyscanner," ");
847 }
848 else // even slashes are verbatim (e.g. \verbatim, \code)
849 {
850 REJECT;
851 }
852 }
853<Verbatim,VerbatimCode>. { /* any other character */
854 copyToOutput(yyscanner,yytext,yyleng);
855 }
856<SkipString>\\. { /* escaped character in string */
857 if (yyextra->lang==SrcLangExt::Fortran || yyextra->lang==SrcLangExt::VHDL)
858 {
859 unput(yytext[1]);
860 copyToOutput(yyscanner,yytext,1);
861 }
862 else
863 {
864 copyToOutput(yyscanner,yytext,yyleng);
865 }
866 }
867<SkipString>"\"" { /* end of string */
868 copyToOutput(yyscanner,yytext,yyleng);
869 BEGIN(yyextra->stringContext);
870 }
871<SkipString>. { /* any other string character */
872 copyToOutput(yyscanner,yytext,yyleng);
873 }
874<SkipString>\n { /* new line inside string (illegal for some compilers) */
875 copyToOutput(yyscanner,yytext,yyleng);
876 }
877<SkipVerbString>[^"\n]+ {
878 copyToOutput(yyscanner,yytext,yyleng);
879 }
880<SkipVerbString>\"\" { // escaped quote
881 copyToOutput(yyscanner,yytext,yyleng);
882 }
883<SkipVerbString>"\"" { /* end of string */
884 copyToOutput(yyscanner,yytext,yyleng);
885 BEGIN(yyextra->stringContext);
886 }
887<SkipVerbString>. {
888 copyToOutput(yyscanner,yytext,yyleng);
889 }
890<SkipVerbString>\n {
891 copyToOutput(yyscanner,yytext,yyleng);
892 }
893<SkipChar>\\. { /* escaped character */
894 if (yyextra->lang==SrcLangExt::Fortran || yyextra->lang==SrcLangExt::VHDL)
895 {
896 unput(yytext[1]);
897 copyToOutput(yyscanner,yytext,1);
898 }
899 else
900 {
901 copyToOutput(yyscanner,yytext,yyleng);
902 }
903 }
904<SkipChar>' { /* end of character literal */
905 copyToOutput(yyscanner,yytext,yyleng);
906 BEGIN(yyextra->charContext);
907 }
908<SkipChar>. { /* any other string character */
909 copyToOutput(yyscanner,yytext,yyleng);
910 }
911<SkipChar>\n { /* new line character */
912 copyToOutput(yyscanner,yytext,yyleng);
913 }
914
915<CComment,CNComment>[^ `~<\\!@*\n{\"'\/-`]* { /* anything that is not a '*' or command */
916 copyToOutput(yyscanner,yytext,yyleng);
917 }
918<CComment,CNComment>^{B}*"*"+[^*\/<\\@\n{\"`]* { /* stars without slashes */
919 if (yyextra->lang==SrcLangExt::Markdown) REJECT;
920 yyextra->col = computeIndent(yytext);
921 if (yyextra->col>yyextra->blockHeadCol)
922 {
923 //printf("new blockHeadCol=%d\n",yyextra->blockHeadCol);
924 yyextra->blockHeadCol=yyextra->col;
925 }
926 copyToOutput(yyscanner,yytext,yyleng);
927 }
928<CComment>"'''" |
929<CComment>"\"\"\"" { /* end of Python docstring */
930 if (yyextra->lang!=SrcLangExt::Python)
931 {
932 REJECT;
933 }
934 else if (yyextra->pythonDocStringChar != yytext[0])
935 {
936 copyToOutput(yyscanner,yytext,yyleng);
937 }
938 else
939 {
940 yyextra->nestingCount--;
941 yyextra->pythonDocString = FALSE;
942 yyextra->pythonDocStringChar = '\0';
943 copyToOutput(yyscanner,yytext,yyleng);
944 BEGIN(Scan);
945 }
946 }
947<CComment,CNComment>\n { /* new line in comment */
948 copyToOutput(yyscanner,yytext,yyleng);
949 /* in case of Fortran always end of comment */
950 if (yyextra->lang==SrcLangExt::Fortran)
951 {
952 BEGIN(Scan);
953 }
954 }
955<CComment,CNComment>"/""/"+/"*/" { /* we are already in C-comment so not a start of a nested comment but
956 * just the end of the comment (the end part is handled later). */
957 copyToOutput(yyscanner,yytext,yyleng);
958 }
959<CComment,CNComment>"/"+"*" { /* nested C comment */
960 if (yyextra->lang==SrcLangExt::Python ||
961 yyextra->lang==SrcLangExt::Markdown)
962 {
963 REJECT;
964 }
965 yyextra->nestingCount++;
966 yyextra->commentStack.push(yyextra->lineNr);
967 copyToOutput(yyscanner,yytext,yyleng);
968 }
969<CComment,CNComment>^{B}*"*"+"/" |
970<CComment,CNComment>"*"+"/" { /* end of C comment */
971 if (yyextra->lang==SrcLangExt::Python ||
972 yyextra->lang==SrcLangExt::Markdown)
973 {
974 REJECT;
975 }
976 else
977 {
978 copyToOutput(yyscanner,yytext,yyleng);
979 yyextra->nestingCount--;
980 if (yyextra->nestingCount<=0)
981 {
982 BEGIN(Scan);
983 }
984 else
985 {
986 //yyextra->nestingCount--;
987 yyextra->commentStack.pop();
988 }
989 }
990 }
991 /* Python an VHDL share CComment,CNComment, so special attention for ending comments is required */
992<CComment,CNComment>"\n"/[ \t]*"#" {
993 if (yyextra->lang!=SrcLangExt::VHDL)
994 {
995 REJECT;
996 }
997 else
998 {
999 if (yyextra->vhdl) // inside --! comment
1000 {
1001 yyextra->vhdl = FALSE;
1002 copyToOutput(yyscanner,yytext,yyleng);
1003 BEGIN(Scan);
1004 }
1005 else // C-type comment
1006 {
1007 REJECT;
1008 }
1009 }
1010 }
1011<CComment,CNComment>"\n"/[ \t]*"-" {
1012 if (yyextra->lang!=SrcLangExt::Python || yyextra->pythonDocString)
1013 {
1014 REJECT;
1015 }
1016 else
1017 {
1018 copyToOutput(yyscanner,yytext,yyleng);
1019 BEGIN(Scan);
1020 }
1021 }
1022<CComment,CNComment>"\n"/[ \t]*[^ \t#\-] {
1023 if (yyextra->lang==SrcLangExt::Python)
1024 {
1025 if (yyextra->pythonDocString)
1026 {
1027 REJECT;
1028 }
1029 else
1030 {
1031 copyToOutput(yyscanner,yytext,yyleng);
1032 BEGIN(Scan);
1033 }
1034 }
1035 else if (yyextra->lang==SrcLangExt::VHDL)
1036 {
1037 if (yyextra->vhdl) // inside --! comment
1038 {
1039 yyextra->vhdl = FALSE;
1040 copyToOutput(yyscanner,yytext,yyleng);
1041 BEGIN(Scan);
1042 }
1043 else // C-type comment
1044 {
1045 REJECT;
1046 }
1047 }
1048 else
1049 {
1050 REJECT;
1051 }
1052 }
1053 /* removed for bug 674842 (bug was introduced in rev 768)
1054<CComment,CNComment>"'" {
1055 yyextra->charContext = YY_START;
1056 copyToOutput(yyscanner,yytext,yyleng);
1057 BEGIN(SkipChar);
1058 }
1059<CComment,CNComment>"\"" {
1060 yyextra->stringContext = YY_START;
1061 copyToOutput(yyscanner,yytext,yyleng);
1062 BEGIN(SkipString);
1063 }
1064 */
1065<CComment,CNComment>{CMD}"~"[a-z_A-Z-]* { // language switch command
1066 if (yyextra->lang!=SrcLangExt::Markdown) REJECT;
1067 QCString langId = QCString(yytext).mid(2);
1068 if (!langId.isEmpty() &&
1069 qstricmp(Config_getEnumAsString(OUTPUT_LANGUAGE),langId)!=0)
1070 { // enable language specific section
1071 if (!Config_isAvailableEnum(OUTPUT_LANGUAGE,langId))
1072 {
1073 warn(yyextra->fileName,yyextra->lineNr,
1074 "non supported language '{}' specified in '{}'",langId,QCString(yytext).stripWhiteSpace());
1075 }
1076 BEGIN(SkipLang);
1077 }
1078 }
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
1079<CComment,CNComment>{CMD}{CMD} |
1080<CComment,CNComment>. {
1081 copyToOutput(yyscanner,yytext,yyleng);
1082 }
1083<SkipLang>{CMD}"~"[a-zA-Z-]* { /* language switch */
1084 QCString langId(&yytext[2]);
1085 if (!langId.isEmpty() && !Config_isAvailableEnum(OUTPUT_LANGUAGE,langId))
1086 {
1087 warn(yyextra->fileName,yyextra->lineNr,
1088 "non supported language '{}' specified in '{}'",langId,QCString(yytext).stripWhiteSpace());
1089 }
1090 else if (langId.isEmpty() ||
1091 qstricmp(Config_getEnumAsString(OUTPUT_LANGUAGE),langId)==0)
1092 { // enable language specific section
1093 BEGIN(CComment);
1094 }
1095 }
1096<SkipLang>[^*@\\\n]* { /* any character not a *, @, backslash or new line */
1097 }
1098<SkipLang>\n { /* new line in language block, needed for keeping track of line numbers */
1099 copyToOutput(yyscanner,yytext,yyleng);
1100 }
1101<SkipLang>. { /* any other character */
1102 }
1103<SComment>^[ \t]*{CPPC}"/"{SLASHopt}/\n {
1104 replaceComment(yyscanner,0);
1105 }
1106<SComment>\n[ \t]*{CPPC}"/"{SLASHopt}/\n {
1107 replaceComment(yyscanner,1);
1108 }
1109<SComment>^[ \t]*{CPPC}"/"[^\/\n]/.*\n {
1110 replaceComment(yyscanner,0);
1111 yyextra->readLineCtx=YY_START;
1112 YY_CURRENT_BUFFER->yy_at_bol=1;
1113 BEGIN(ReadLine);
1114 }
1115<SComment>\n[ \t]*{CPPC}[\/!]("<")?[ \t]*{CMD}"}".*\n {
1116 /* See Bug 752712: end the multiline comment when finding a @} or \} command */
1117 copyToOutput(yyscanner," */");
1118 copyToOutput(yyscanner,yytext,yyleng);
1119 yyextra->inSpecialComment=false;
1120 yyextra->inRoseComment=false;
1121 BEGIN(Scan);
1122 }
1123<SComment>\n[ \t]*{CPPC}"/"[^\\@\/\n]/.*\n {
1124 replaceComment(yyscanner,1);
1125 yyextra->readLineCtx=YY_START;
1126 YY_CURRENT_BUFFER->yy_at_bol=1;
1127 BEGIN(ReadLine);
1128 }
1129<SComment>^[ \t]*{CPPC}"!" | // just //!
1130<SComment>^[ \t]*{CPPC}"!<"/.*\n | // or //!< something
1131<SComment>^[ \t]*{CPPC}"!"[^<]/.*\n { // or //!something
1132 replaceComment(yyscanner,0);
1133 yyextra->readLineCtx=YY_START;
1134 YY_CURRENT_BUFFER->yy_at_bol=1;
1135 BEGIN(ReadLine);
1136 }
1137<SComment>\n[ \t]*{CPPC}"!" |
1138<SComment>\n[ \t]*{CPPC}"!<"/.*\n |
1139<SComment>\n[ \t]*{CPPC}"!"[^<\n]/.*\n {
1140 replaceComment(yyscanner,1);
1141 yyextra->readLineCtx=YY_START;
1142 YY_CURRENT_BUFFER->yy_at_bol=1;
1143 BEGIN(ReadLine);
1144 }
1145<SComment>^[ \t]*{CPPC}"##"/.*\n {
1146 if (!yyextra->inRoseComment)
1147 {
1148 REJECT;
1149 }
1150 else
1151 {
1152 replaceComment(yyscanner,0);
1153 yyextra->readLineCtx=YY_START;
1154 YY_CURRENT_BUFFER->yy_at_bol=1;
1155 BEGIN(ReadLine);
1156 }
1157 }
1158<SComment>\n[ \t]*{CPPC}"##"/.*\n {
1159 if (!yyextra->inRoseComment)
1160 {
1161 REJECT;
1162 }
1163 else
1164 {
1165 replaceComment(yyscanner,1);
1166 yyextra->readLineCtx=YY_START;
1167 YY_CURRENT_BUFFER->yy_at_bol=1;
1168 BEGIN(ReadLine);
1169 }
1170 }
1171<SComment>\n { /* end of special comment */
1172 copyToOutput(yyscanner," */");
1173 copyToOutput(yyscanner,yytext,yyleng);
1174 yyextra->inSpecialComment=FALSE;
1175 yyextra->inRoseComment=FALSE;
1176 yyextra->insertCppCommentMarker=false;
1177 yyextra->readLineCtx = Scan; // reset, otherwise there will be problems with:
1178 // static void handleCondSectionId
1179 BEGIN(Scan);
1180 }
1181<ReadLine>{CCS}"*" {
1182 copyToOutput(yyscanner,"/&zwj;**");
1183 }
1184<ReadLine>{CCE} {
1185 copyToOutput(yyscanner,"*&zwj;/");
1186 }
1187<ReadLine,CopyLine>"*" {
1188 copyToOutput(yyscanner,yytext,yyleng);
1189 }
1190<ReadLine,CopyLine>{RL} {
1191 copyToOutput(yyscanner,yytext,yyleng);
1192 }
1193<ReadLine,CopyLine>{RL}/{B}{CMD}"ilinebr"{B} {
1194 copyToOutput(yyscanner,yytext,yyleng);
1195 }
1196<ReadLine,CopyLine>{RLopt}/\n {
1197 copyToOutput(yyscanner,yytext,yyleng);
1198 yyextra->insertCppCommentMarker=false;
1199 BEGIN(yyextra->readLineCtx);
1200 }
1201<CComment,CNComment,ReadLine>"\<" { /* escaped html comment */
1202 copyToOutput(yyscanner,yytext,yyleng);
1203 }
1204<CComment,CNComment,ReadLine>{CMD}{CMD}[~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
1205 copyToOutput(yyscanner,yytext,yyleng);
1206 }
1207
1208<CComment,ReadLine,IncludeFile>{CMD}("include"{OPTS}|"includedoc"{OPTS}*) {
1209 if (!parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)})) REJECT;
1210 yyextra->includeCtx = YY_START;
1211 yyextra->firstIncludeLine = true;
1212 yyextra->insertCommentCol = yyextra->col;
1213 if (!yyextra->insertCppCommentMarker && (yyextra->includeCtx==ReadLine || yyextra->includeCtx==IncludeFile))
1214 {
1215 yyextra->insertCppCommentMarker = yyextra->mlBrief;
1216 }
1217 //printf("blockHeadCol=%d insertCommentCol=%d\n",yyextra->blockHeadCol, yyextra->insertCommentCol);
1218 BEGIN(IncludeDoc);
1219 }
1220<CComment,ReadLine,IncludeFile>{CMD}("snippet"{OPTS}|"snippetdoc"{OPTS}*) {
1221 if (!parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)})) REJECT;
1222 yyextra->includeCtx = YY_START;
1223 yyextra->firstIncludeLine = true;
1224 yyextra->insertCommentCol = yyextra->col;
1225 if (!yyextra->insertCppCommentMarker && (yyextra->includeCtx==ReadLine || yyextra->includeCtx==IncludeFile))
1226 {
1227 yyextra->insertCppCommentMarker = yyextra->mlBrief;
1228 }
1229 //printf("blockHeadCol=%d insertCommentCol=%d\n",yyextra->blockHeadCol, yyextra->insertCommentCol);
1230 BEGIN(SnippetDoc);
1231 }
1232<IncludeDoc,SnippetDoc>{B}*
1233<IncludeDoc>{FILEMASK}|"\""[^\n\"]+"\"" {
1234 QCString fileName=yytext;
1235 if (yytext[0]=='"')
1236 {
1237 fileName=fileName.mid(1,fileName.length()-2); // strip quotes
1238 }
1239 if (readIncludeFile(yyscanner,fileName,""))
1240 {
1241 BEGIN(IncludeFile);
1242 }
1243 else
1244 {
1245 BEGIN(yyextra->includeCtx);
1246 }
1247 }
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:153
1248<SnippetDoc>({FILEMASK}|"\""[^\n\"]+"\""){B}+ {
1249 yyextra->snippetFileName=yytext;
1250 yyextra->snippetFileName=yyextra->snippetFileName.stripWhiteSpace();
1251 if (yyextra->snippetFileName == "this") yyextra->snippetFileName=yyextra->fileName;
1252 yyextra->snippetName = "";
1253 BEGIN(SnippetDocTag);
1254 }
1255<SnippetDocTag>[^\\@\n]+ {
1256 yyextra->snippetName += yytext;
1257 }
1258<SnippetDocTag>{CMD} {
1259 yyextra->snippetName += yytext;
1260 }
1261<SnippetDocTag>(\n|{CMD}"ilinebr") {
1262 for (int i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
1263 yyextra->snippetName = yyextra->snippetName.stripWhiteSpace();
1264 QCString blockId = "["+yyextra->snippetName+"]";
1265 if (readIncludeFile(yyscanner,yyextra->snippetFileName,blockId))
1266 {
1267 BEGIN(IncludeFile);
1268 }
1269 else
1270 {
1271 BEGIN(yyextra->includeCtx);
1272 }
1273 }
1274
1275<IncludeDoc,SnippetDoc>\n {
1276 copyToOutput(yyscanner,yytext,yyleng);
1277 insertCommentStart(yyscanner);
1278 // missing file name
1279 //warn(yyextra->fileName,yyextra->lineNr,"Found \\include{{doc}} command without valid file name argument");
1280 BEGIN(yyextra->includeCtx);
1281 }
1282<IncludeDoc,SnippetDoc>. { // invalid character
1283 copyToOutput(yyscanner,yytext,yyleng);
1284 BEGIN(yyextra->includeCtx);
1285 }
1286<CComment,ReadLine,IncludeFile>{CMD}"cond"/[^a-z_A-Z0-9] { // conditional section
1287 yyextra->condCtx = YY_START;
1288 BEGIN(CondLine);
1289 }
1290<CComment,ReadLine,IncludeFile>{CMD}"endcond"/[^a-z_A-Z0-9] { // end of conditional section
1291 bool oldSkip=yyextra->skip;
1292 endCondSection(yyscanner);
1293 if (YY_START==CComment && oldSkip && !yyextra->skip)
1294 {
1295 //printf("** Adding start of comment!\n");
1296 if (yyextra->lang!=SrcLangExt::Python &&
1297 yyextra->lang!=SrcLangExt::VHDL &&
1298 yyextra->lang!=SrcLangExt::Markdown &&
1299 yyextra->lang!=SrcLangExt::Fortran)
1300 {
1301 yyextra->outBuf+='/';
1302 yyextra->outBuf+='*';
1303 yyextra->col+=2;
1304 if (yyextra->specialComment)
1305 {
1306 yyextra->outBuf+='*';
1307 yyextra->col++;
1308 }
1309 }
1310 }
1311 }
1312<CondLine>[!()&| \ta-z_A-Z0-9.\-]+ {
1313 handleCondSectionId(yyscanner,yytext);
1314 }
1315<CComment,ReadLine,IncludeFile>{CMD}"cond"{WSopt}/\n {
1316 yyextra->condCtx=YY_START;
1317 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
1318 }
1319<CondLine>\n |
1320<CondLine>. { // forgot section id?
1321 handleCondSectionId(yyscanner," "); // fake section id causing the section to be hidden unconditionally
1322 if (*yytext=='\n') { copyToOutput(yyscanner,"\n");}
1323 }
1324<CComment,ReadLine,IncludeFile,Verbatim,VerbatimCode>{CMD}[a-z_A-Z][a-z_A-Z0-9-]* { // expand alias without arguments
1325 replaceAliases(yyscanner,yytext,YY_START==ReadLine && yyextra->readLineCtx==SComment);
1326 }
1327<CComment,ReadLine,IncludeFile,Verbatim,VerbatimCode>{B}?{CMD}"ilinebr"{B}{CMD}"ialias{" { // expand alias with arguments
1328 yyextra->lastBlockContext=YY_START;
1329 yyextra->blockCount=1;
1330 int extraSpace = (yytext[0]==' '? 1:0);
1331 yyextra->aliasString=yytext+9+extraSpace;
1332 yyextra->aliasCmd=yytext+9+extraSpace;
1333 yyextra->lastEscaped=0;
1334 BEGIN( ReadAliasArgs );
1335 }
1336<CComment,ReadLine,IncludeFile,Verbatim,VerbatimCode>{CMD}[a-z_A-Z][a-z_A-Z0-9-]*"{" { // expand alias with arguments
1337 yyextra->lastBlockContext=YY_START;
1338 yyextra->blockCount=1;
1339 yyextra->aliasString=yytext;
1340 yyextra->aliasCmd=yytext;
1341 yyextra->lastEscaped=0;
1342 BEGIN( ReadAliasArgs );
1343 }
1344<ReadAliasArgs>^[ \t]*"*" { // skip leading *
1345 }
1346<ReadAliasArgs>^[ \t]*{CPPC}[/!]/[^\n]* { // skip leading special comments (see bug 618079)
1347 }
1348<ReadAliasArgs>[^{}\n\\\*]+ {
1349 yyextra->aliasString+=yytext;
1350 yyextra->lastEscaped=FALSE;
1351 }
1352<ReadAliasArgs>"\\" {
1353 if (yyextra->lastEscaped) yyextra->lastEscaped=FALSE;
1354 else yyextra->lastEscaped=TRUE;
1355 yyextra->aliasString+=yytext;
1356 }
1357<ReadAliasArgs>{CMD}("endverbatim"|"endiliteral"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}"|"f)") { /* end of verbatim block */
1358 yyextra->aliasString+=yytext;
1359 if (yyextra->inVerbatim && &yytext[1]==yyextra->blockName)
1360 // For verbatim sections we do not support matching end block markers inside
1361 // alias arguments. Instead this will end the verbatim block.
1362 // This is needed to support an alias definition
1363 // like startalign=" \latexonly\noalign{\endlatexonly" were otherwise
1364 // the scanner would try to find a matching closing brace for noalign and then
1365 // skip over the \endlatexonly command.
1366 {
1367 copyToOutput(yyscanner,yyextra->aliasString.view());
1368 yyextra->inVerbatim=false;
1369 BEGIN(yyextra->lastCommentContext);
1370 }
1371 }
1372<ReadAliasArgs>\n {
1373 yyextra->aliasString+=yytext;
1374 yyextra->lastEscaped=FALSE;
1375 if (yyextra->inVerbatim) // for verbatim sections we do not support multi-line
1376 // alias arguments.
1377 {
1378 copyToOutput(yyscanner,yyextra->aliasString.view());
1379 BEGIN( yyextra->lastBlockContext );
1380 }
1381 }
1382<ReadAliasArgs>"{" {
1383 yyextra->aliasString+=yytext;
1384 if (!yyextra->lastEscaped) yyextra->blockCount++;
1385 yyextra->lastEscaped=FALSE;
1386 }
1387<ReadAliasArgs>"}" {
1388 yyextra->aliasString+=yytext;
1389 if (!yyextra->lastEscaped) yyextra->blockCount--;
1390 if (yyextra->blockCount==0)
1391 {
1392 replaceAliases(yyscanner,yyextra->aliasString.view(),
1393 yyextra->lastBlockContext==ReadLine && yyextra->readLineCtx==SComment);
1394 BEGIN( yyextra->lastBlockContext );
1395 }
1396 yyextra->lastEscaped=FALSE;
1397 }
1398<ReadAliasArgs>. {
1399 yyextra->aliasString+=yytext;
1400 yyextra->lastEscaped=FALSE;
1401 }
1402<CopyLine>. {
1403 copyToOutput(yyscanner,yytext,yyleng);
1404 }
1405<CopyLine>\n {
1406 copyToOutput(yyscanner,yytext,yyleng);
1407 yyextra->insertCppCommentMarker=false;
1408 BEGIN(yyextra->readLineCtx);
1409 }
1410<ReadLine>{CMD}{CMD} |
1411<ReadLine>. {
1412 copyToOutput(yyscanner,yytext,yyleng);
1413 }
1414<IncludeFile>. {
1415 copyToOutput(yyscanner,yytext,yyleng);
1416 }
1417<IncludeFile>\n {
1418 copyToOutput(yyscanner,yytext,yyleng);
1419 insertCommentStart(yyscanner);
1420 }
1421<*>. {
1422 copyToOutput(yyscanner,yytext,yyleng);
1423 }
1424<<EOF>> {
1425 if (YY_START == ReadAliasArgs)
1426 {
1427 warn(yyextra->fileName,yyextra->lineNr,
1428 "Reached end of file while still searching closing '}}' of an alias argument (probable start: '{}')",
1429 yyextra->aliasCmd);
1430 }
1431 else if (YY_START==Verbatim || YY_START==VerbatimCode)
1432 {
1433 warn(yyextra->fileName,yyextra->lineNr,
1434 "Reached end of file while still searching closing '{}' of a verbatim block starting at line {}",
1435 yyextra->blockName,yyextra->verbatimLine);
1436 }
1437 if (yyextra->includeStack.empty())
1438 {
1439 yyextra->insertCppCommentMarker=false;
1440 yyterminate();
1441 }
1442 else // switch back to parent file
1443 {
1444 std::unique_ptr<commentcnv_FileState> &fs = yyextra->includeStack.back();
1445 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
1446 yy_switch_to_buffer(fs->bufState, yyscanner);
1447 yy_delete_buffer(oldBuf, yyscanner);
1448 BEGIN(fs->oldState);
1449 yyextra->fileName = fs->oldFileName;
1450 yyextra->lineNr = fs->oldLineNr;
1451 yyextra->inBuf = fs->oldFileBuf;
1452 yyextra->inBufPos = fs->oldFileBufPos;
1453 yyextra->includeCtx = fs->oldIncludeCtx;
1454 QCString lineStr= " \\ifile \""+yyextra->fileName+"\" \\iline "+QCString().setNum(yyextra->lineNr)+" ";
1455 if (fs->oldRaiseLvl!=yyextra->raiseLevel)
1456 {
1457 lineStr+="\\iraise " + std::to_string(fs->oldRaiseLvl)+ " ";
1458 }
1459 if (fs->oldRaiseLbl!=yyextra->raiseLabel)
1460 {
1461 lineStr+="\\iprefix \"" + fs->oldRaiseLbl + "\" ";
1462 }
1463 lineStr+="\\ilinebr ";
1464 yyextra->raiseLevel = fs->oldRaiseLvl;
1465 yyextra->raiseLabel = fs->oldRaiseLbl;
1466 copyToOutput(yyscanner,lineStr.view());
1467 yyextra->includeStack.pop_back();
1468 //printf("<<EOF>> switch back to %s line %d inbufPos=%d outbufPos=%d\n",
1469 // qPrint(yyextra->fileName),yyextra->lineNr,yyextra->inBufPos,yyextra->outBuf.curPos());
1470 }
1471 }
QCString & setNum(short n)
Definition qcstring.h:444
std::string_view view() const
Definition qcstring.h:161
#define yyterminate()
1472 /*
1473<*>\n { fprintf(stderr,"Lex scanner %s (%s) default rule newline for state %s.\n", __FILE__, qPrint(yyextra->fileName),stateToString(YY_START));}
1474 */
1475%%
1476
1477static bool parseIncludeOptions(yyscan_t yyscanner,std::string_view s)
1478{
1479 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1480
1481 //printf("parseIncludeOptions=%s\n",qPrint(QCString(s)));
1482 size_t optIdxStart = s.find('{');
1483 size_t optIdxEnd = optIdxStart!=std::string::npos ? s.find("}",optIdxStart+1) : std::string::npos;
1484 std::string cmdName;
1485 StringVector optList;
1486 if (optIdxStart == std::string::npos) // no options
1487 {
1488 cmdName = stripWhiteSpace(s.substr(1)); // to remove {CMD}
1489 }
1490 else // options present
1491 {
1492 cmdName = stripWhiteSpace(s.substr(1,optIdxStart-1)); // to remove {CMD}
1493 optList = split(std::string{s.substr(optIdxStart+1,optIdxEnd-optIdxStart-1)},",");
1494 }
1495 bool isDoc = cmdName=="includedoc" || cmdName=="snippetdoc";
1496 for (const auto &opt : optList)
1497 {
1498 if (stripWhiteSpace(opt)==std::string_view{"doc"})
1499 {
1500 isDoc=true;
1501 break;
1502 }
1503 }
1504
1505 if (isDoc)
1506 {
1507 for (const auto &opt : optList)
1508 {
1509 std::string_view locOpt = stripWhiteSpace(opt);
1510 size_t posEqual = locOpt.find('=');
1511 std::string_view option = posEqual!=std::string::npos ? stripWhiteSpace(locOpt.substr(0,posEqual)) : locOpt;
1512 std::string_view value = posEqual!=std::string::npos ? stripWhiteSpace(locOpt.substr(posEqual+1)) : std::string_view();
1513
1514 if (option==std::string_view{"doc"} && value.empty())
1515 {
1516 }
1517 else if (option==std::string_view{"raise"} && !value.empty())
1518 {
1519 yyextra->raiseIncrement = atoi(value.data());
1520 if (yyextra->raiseLevel+yyextra->raiseIncrement>=SectionType::MaxLevel) // check range
1521 {
1522 warn(yyextra->fileName,yyextra->lineNr,"Raising section level from {} to {}, exceeds allowed range [0-{}], adjusting",
1523 yyextra->raiseLevel,yyextra->raiseLevel+yyextra->raiseIncrement,SectionType::MaxLevel-1);
1524 yyextra->raiseIncrement = std::max(0,SectionType::MaxLevel-1-yyextra->raiseLevel);
1525 }
1526 }
1527 else if (option==std::string_view{"prefix"} && !value.empty())
1528 {
1529 yyextra->raisePrefix = value;
1530 }
1531 else
1532 {
1533 warn(yyextra->fileName,yyextra->lineNr,"Unsupported option '{}' for {} command",option, cmdName);
1534 }
1535 }
1536 }
1537
1538 return isDoc;
1539}
1540
1541
1542static void replaceCommentMarker(yyscan_t yyscanner,std::string_view s)
1543{
1544 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1545 if (s.empty()) return;
1546 size_t p = 0;
1547 size_t len = s.length();
1548 char c = 0;
1549 // copy leading blanks
1550 while (p<len && (c=s[p]) && (c==' ' || c=='\t' || c=='\n'))
1551 {
1552 yyextra->outBuf+=c;
1553 if (c=='\n') { yyextra->lineNr++; yyextra->col=0; } else { yyextra->col++; }
1554 p++;
1555 }
1556 // replace start of comment marker by blanks and the last character by a *
1557 int blanks=0;
1558 while (p<len && (c=s[p]) && (c=='/' || c=='!' || c=='#'))
1559 {
1560 blanks++;
1561 p++;
1562 if (p<len && s[p]=='<') // comment-after-item marker
1563 {
1564 blanks++;
1565 p++;
1566 }
1567 if (c=='!') // end after first !
1568 {
1569 break;
1570 }
1571 }
1572 if (blanks>0)
1573 {
1574 while (blanks>2)
1575 {
1576 yyextra->outBuf+=' ';
1577 yyextra->col++;
1578 blanks--;
1579 }
1580 if (blanks>1) { yyextra->outBuf+='*'; yyextra->col++; }
1581 yyextra->outBuf+=' ';
1582 yyextra->col++;
1583 }
1584 // copy comment line to output
1585 yyextra->outBuf+=s.substr(p);
1586 yyextra->col+=s.substr(p).length();
1587}
1588
1589static inline int computeIndent(const char *s)
1590{
1591 int col=0;
1592 int tabSize=Config_getInt(TAB_SIZE);
1593 const char *p=s;
1594 char c = 0;
1595 while ((c=*p++))
1596 {
1597 if (c==' ') col++;
1598 else if (c=='\t') col+=tabSize-(col%tabSize);
1599 else break;
1600 }
1601 return col;
1602}
1603
1604static inline void copyToOutput(yyscan_t yyscanner,std::string_view s)
1605{
1606 int tabSize=Config_getInt(TAB_SIZE);
1607 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1608 size_t len = s.length();
1609 if (yyextra->skip) // only add newlines.
1610 {
1611 for (size_t i=0;i<len;i++)
1612 {
1613 switch(s[i])
1614 {
1615 case '\n':
1616 yyextra->outBuf+='\n';
1617 yyextra->lineNr++;
1618 yyextra->col=0;
1619 break;
1620 case '\t':
1621 yyextra->col+=tabSize-(yyextra->col%tabSize);
1622 break;
1623 default:
1624 yyextra->col++;
1625 break;
1626 }
1627 }
1628 }
1629 else if (len>0)
1630 {
1631 yyextra->outBuf+=s;
1632 for (size_t i=0;i<len;i++)
1633 {
1634 switch (s[i])
1635 {
1636 case '\n': yyextra->col=0;
1637 //fprintf(stderr,"---> copy %d\n",g_lineNr);
1638 yyextra->lineNr++; break;
1639 case '\t': yyextra->col+=tabSize-(yyextra->col%tabSize); break;
1640 default: yyextra->col++; break;
1641 }
1642 }
1643 }
1644}
1645
1646static inline void copyToOutput(yyscan_t yyscanner,const char *s,int len)
1647{
1648 copyToOutput(yyscanner,std::string_view{s,(size_t)len});
1649}
1650
1651static void clearCommentStack(yyscan_t yyscanner)
1652{
1653 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1654 while (!yyextra->commentStack.empty()) yyextra->commentStack.pop();
1655}
1656
1657static void startCondSection(yyscan_t yyscanner,const QCString &sectId)
1658{
1659 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1660 //printf("startCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1661 CondParser prs;
1662 bool expResult = prs.parse(yyextra->fileName,yyextra->lineNr,sectId);
1663 yyextra->condStack.emplace(yyextra->lineNr,sectId,yyextra->skip);
1664 if (!expResult) // not enabled
1665 {
1666 yyextra->skip=TRUE;
1667 }
1668}
1669
1670static void endCondSection(yyscan_t yyscanner)
1671{
1672 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1673 if (yyextra->condStack.empty())
1674 {
1675 warn(yyextra->fileName,yyextra->lineNr,"Found \\endcond command without matching \\cond");
1676 yyextra->skip=FALSE;
1677 }
1678 else
1679 {
1680 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
1681 yyextra->skip=ctx.skip;
1682 yyextra->condStack.pop();
1683 }
1684 //printf("endCondSection: skip=%d stack=%d\n",g_skip,g_condStack.count());
1685}
1686
1687static void handleCondSectionId(yyscan_t yyscanner,const char *expression)
1688{
1689 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1690 bool oldSkip=yyextra->skip;
1691 startCondSection(yyscanner,QCString(expression));
1692 if ((yyextra->condCtx==CComment || yyextra->readLineCtx==SComment) &&
1693 !oldSkip && yyextra->skip)
1694 {
1695 if (yyextra->lang!=SrcLangExt::Python &&
1696 yyextra->lang!=SrcLangExt::VHDL &&
1697 yyextra->lang!=SrcLangExt::Markdown &&
1698 yyextra->lang!=SrcLangExt::Fortran)
1699 {
1700 yyextra->outBuf+='*';
1701 yyextra->outBuf+='/';
1702 yyextra->col+=2;
1703 }
1704 }
1705 if (yyextra->readLineCtx==SComment)
1706 {
1707 BEGIN(SComment);
1708 }
1709 else
1710 {
1711 BEGIN(yyextra->condCtx);
1712 }
1713}
1714
1715/** Returns the section of text, in between a pair of markers.
1716 * Full lines are returned, excluding the lines on which the markers appear.
1717 * \sa routine lineBlock
1718 */
1719static QCString extractBlock(const QCString &text,const QCString &marker,int &blockPos)
1720{
1721 QCString result;
1722 int p=0,i=-1;
1723 bool found=FALSE;
1724
1725 // find the character positions of the markers
1726 int m1 = text.find(marker);
1727 if (m1==-1) return result;
1728 int m2 = text.find(marker,m1+static_cast<int>(marker.length()));
1729 if (m2==-1) return result;
1730
1731 // find start and end line positions for the markers
1732 int l1=-1,l2=-1;
1733 while (!found && (i=text.find('\n',p))!=-1)
1734 {
1735 found = (p<=m1 && m1<i); // found the line with the start marker
1736 p=i+1;
1737 }
1738 l1=p;
1739 blockPos=p;
1740 int lp=i;
1741 if (found)
1742 {
1743 while ((i=text.find('\n',p))!=-1)
1744 {
1745 if (p<=m2 && m2<i) // found the line with the end marker
1746 {
1747 l2=p;
1748 break;
1749 }
1750 p=i+1;
1751 lp=i;
1752 }
1753 }
1754 if (l2==-1) // marker at last line without newline (see bug706874)
1755 {
1756 l2=lp;
1757 }
1758 return l2>l1 ? text.mid(l1,l2-l1) : QCString();
1759}
1760
1761static void insertCommentStart(yyscan_t yyscanner)
1762{
1763 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1764 int startCol=yyextra->blockHeadCol;
1765 int contentCol=yyextra->insertCommentCol;
1766 int markerSpace=contentCol-startCol;
1767 //printf("insertCommentStart startCol=%d contentCol=%d mlBrief=%d insertCppCommentMarker=%d\n",
1768 // yyextra->blockHeadCol,yyextra->insertCommentCol,yyextra->mlBrief,yyextra->insertCppCommentMarker);
1769 std::string marker;
1770 if (yyextra->lang==SrcLangExt::Python) // need to insert # or space
1771 {
1772 if (yyextra->pythonDocString) // """! style comment
1773 {
1774 marker=" ";
1775 }
1776 else
1777 {
1778 marker="# ";
1779 }
1780 }
1781 else if (yyextra->lang==SrcLangExt::Fortran) // need to insert !!
1782 {
1783 marker="!! ";
1784 }
1785 else if (yyextra->lang==SrcLangExt::Markdown)
1786 {
1787 marker=" ";
1788 }
1789 else if (yyextra->insertCppCommentMarker) // need to insert ///
1790 {
1791 marker="/// ";
1792 if (startCol>0)
1793 {
1794 // insert `///` instead of '* '
1795 startCol--;
1796 markerSpace++;
1797 }
1798 }
1799 else // need to insert *
1800 {
1801 marker="* ";
1802 }
1803 int i=0;
1804 for (;i<startCol;i++)
1805 {
1806 copyToOutput(yyscanner," ");
1807 }
1808 if (static_cast<int>(marker.length())<=markerSpace && !yyextra->firstIncludeLine)
1809 {
1810 copyToOutput(yyscanner,marker);
1811 i+=marker.length();
1812 }
1813 for (;i<contentCol;i++)
1814 {
1815 copyToOutput(yyscanner," ");
1816 }
1817 yyextra->firstIncludeLine = false;
1818}
1819
1820static bool readIncludeFile(yyscan_t yyscanner,const QCString &inc,const QCString &blockId)
1821{
1822 //printf("readIncludeFile(inc=%s,blockId=%s)\n",qPrint(inc),qPrint(blockId));
1823 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1824 bool ambig = false;
1825 QCString absFileName = findFilePath(inc,ambig);
1826 FileInfo fi(absFileName.str());
1827 if (!absFileName.isEmpty() && fi.exists() && fi.isFile())
1828 {
1829 if (ambig)
1830 {
1831 warn_doc_error(yyextra->fileName,yyextra->lineNr,"included file name '{}' is ambiguous"
1832 "Possible candidates:\n{}",inc, showFileDefMatches(Doxygen::exampleNameLinkedMap,inc));
1833 }
1834 bool alreadyProcessed = std::any_of(
1835 yyextra->includeStack.begin(),
1836 yyextra->includeStack.end(),
1837 [&absFileName,&blockId](const auto &lfs)
1838 { return lfs->fileName==absFileName && lfs->blockId==blockId; }
1839 );
1840
1841 if (alreadyProcessed)
1842 {
1843 if (!blockId.isEmpty())
1844 {
1845 warn_doc_error(yyextra->fileName,yyextra->lineNr,"recursive usage of '\\snippet{{doc}}' block with name '{}' and file name '{}', skipping",
1846 blockId,absFileName);
1847 }
1848 else
1849 {
1850 warn_doc_error(yyextra->fileName,yyextra->lineNr,"recursive usage of '\\include{{doc}}' with file name '{}', skipping", absFileName);
1851 }
1852 return false;
1853 }
1854
1855 auto fs = std::make_unique<commentcnv_FileState>();
1856 if (!readInputFile(absFileName,fs->fileBuf,false))
1857 {
1858 warn_doc_error(yyextra->fileName,yyextra->lineNr,"\\{}{{doc}} file '{}' could not be read",blockId.isEmpty()?"include":"snippet",absFileName);
1859 fs.reset();
1860 return false;
1861 }
1862 int lineNr=1;
1863 if (!blockId.isEmpty())
1864 {
1865 QCString incText { fs->fileBuf };
1866 int count = incText.contains(blockId.data());
1867 if (count!=2)
1868 {
1869 warn_doc_error(yyextra->fileName,yyextra->lineNr,"block marked with {} for \\snippet{{doc}} should appear twice in file {}, found it {:d} times, skipping",
1870 blockId,absFileName,count);
1871 return false;
1872 }
1873 lineNr = lineBlock(incText, blockId);
1874 int blockPos = 0;
1875 incText = extractBlock(incText, blockId, blockPos);
1876 fs->fileBuf.clear();
1877 if (!incText.isEmpty())
1878 {
1879 fs->fileBuf.append(incText.str());
1880 }
1881 }
1882 int oldRaiseLevel = yyextra->raiseLevel;
1883 QCString oldRaiseLabel = yyextra->raiseLabel;
1884 yyextra->raiseLevel+=yyextra->raiseIncrement;
1885 yyextra->raiseLabel+=yyextra->raisePrefix;
1886 QCString lineStr=" \\ifile \""+absFileName+"\" \\iline " + std::to_string(lineNr)+" ";
1887 if (yyextra->raiseLevel>0)
1888 {
1889 lineStr+="\\iraise " + std::to_string(yyextra->raiseLevel)+" ";
1890 }
1891 if (!yyextra->raiseLabel.isEmpty())
1892 {
1893 lineStr+="\\iprefix \"" + yyextra->raiseLabel + "\" ";
1894 }
1895 lineStr+="\\ilinebr ";
1896 copyToOutput(yyscanner,lineStr.view());
1897
1898 fs->fileName = absFileName;
1899 fs->bufState = YY_CURRENT_BUFFER;
1900 fs->oldLineNr = yyextra->lineNr;
1901 fs->oldFileName = yyextra->fileName;
1902 fs->oldState = yyextra->includeCtx;
1903 fs->oldFileBuf = yyextra->inBuf;
1904 fs->oldFileBufPos = yyextra->inBufPos;
1905 fs->oldIncludeCtx = yyextra->includeCtx;
1906 fs->oldRaiseLvl = oldRaiseLevel;
1907 fs->oldRaiseLbl = oldRaiseLabel;
1908 fs->blockId = blockId;
1909 yy_switch_to_buffer(yy_create_buffer(nullptr, YY_BUF_SIZE, yyscanner),yyscanner);
1910 yyextra->fileName = absFileName;
1911 yyextra->lineNr = lineNr;
1912 yyextra->inBuf = &fs->fileBuf;
1913 yyextra->inBufPos = 0;
1914 yyextra->includeStack.push_back(std::move(fs));
1915 insertCommentStart(yyscanner);
1916 //printf("switched to %s\n",qPrint(fileName));
1917 }
1918 else
1919 {
1920 warn_doc_error(yyextra->fileName,yyextra->lineNr,"\\{}{{doc}} file '{}' not found",blockId.isEmpty()?"include":"snippet",inc);
1921 return false;
1922 }
1923 return true;
1924}
1925
1926/** copies string \a s with length \a len to the output, while
1927 * replacing any alias commands found in the string.
1928 */
1929static void replaceAliases(yyscan_t yyscanner,std::string_view s,bool replaceComment)
1930{
1931 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1932 if (s.empty()) return;
1933 size_t pos = s.find('{');
1934 std::string cmd { s.substr(1, pos!=std::string::npos ? pos-1 : s.length()-1) };
1935 auto &expAlias = yyextra->expandedAliases;
1936 if (std::find(expAlias.begin(),expAlias.end(),cmd)!=std::end(expAlias))
1937 {
1938 copyToOutput(yyscanner,s);
1939 return; // prevent recursive expansion
1940 }
1941 else if (cmd=="ialias")
1942 {
1943 if (s.length()>cmd.length()+3) // \cmd{value}
1944 {
1945 std::string value { s.substr(cmd.length()+2,s.length()-cmd.length()-3) };
1946 //printf("removing value '%s'\n",qPrint(value));
1947 expAlias.erase(std::remove(expAlias.begin(),expAlias.end(),value),expAlias.end());
1948 }
1949 return;
1950 }
1951 std::string result = resolveAliasCmd(s);
1952 if (yyextra->inVerbatim) // inside verbatim blocks (like @code...@endcode) only expand aliases if
1953 // their expansion contains the matching end block marker.
1954 {
1955 std::string blk = yyextra->blockName.str();
1956 assert(!blk.empty());
1957 bool isNamedCommand=isId(blk[0]); // true for e.g. @endcode, false for e.g. ~~~
1958 size_t i=0,p=0;
1959 bool found=false;
1960 while ((i=result.find(blk,p))!=std::string::npos && !found) // for each match of blk in result
1961 {
1962 found = !isNamedCommand || // e.g. '~~~' or '-->'
1963 (i>0 && (result[i-1]=='\\' || result[i-1]=='@') && !isId(result[i+blk.length()])); // e.g. '@endcode' but not ~endcode or @endcodex
1964 p = i+yyextra->blockName.length();
1965 }
1966 //printf("blk=%s result=%s found=%d\n",qPrint(blk),qPrint(result),found);
1967 if (!found) // treat alias as part of the verbatim block
1968 {
1969 copyToOutput(yyscanner,s);
1970 return;
1971 }
1972 }
1973 //printf("replaceAliases(%s)->'%s' replaceComment=%d\n",qPrint(s),qPrint(result),replaceComment);
1974 if (result!=s)
1975 {
1976 if (replaceComment) // In case we are replacing a multiline /// comment by a C style comment
1977 // and we have new lines in the alias argument, we need to place back a /// for each new line
1978 // to prevent breaking the multiline comment into multiple C style comments
1979 {
1980 result = substituteStringView(result,"\n","\n///");
1981 }
1982 expAlias.push_back(cmd);
1983 // add a ialias command to allow expansion of cmd again
1984 result += " \\ilinebr \\ialias{";
1985 result += cmd;
1986 result += "}";
1987 for (int i=(int)result.length()-1; i>=0; i--)
1988 {
1989 unput(result[i]);
1990 }
1991 }
1992 else
1993 {
1994 copyToOutput(yyscanner,result);
1995 }
1996}
1997
1998
1999static int yyread(yyscan_t yyscanner,char *buf,int max_size)
2000{
2001 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2002 int bytesInBuf = static_cast<int>(yyextra->inBuf->size())-yyextra->inBufPos;
2003 int bytesToCopy = std::min(max_size,bytesInBuf);
2004 memcpy(buf,yyextra->inBuf->data()+yyextra->inBufPos,bytesToCopy);
2005 yyextra->inBufPos+=bytesToCopy;
2006 return bytesToCopy;
2007}
2008
2009static void replaceComment(yyscan_t yyscanner,int offset)
2010{
2011 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2012 if (yyextra->mlBrief || yyextra->skip)
2013 {
2014 copyToOutput(yyscanner,yytext,yyleng);
2015 }
2016 else
2017 {
2018 int i=computeIndent(&yytext[offset]);
2019 //printf("i=%d blockHeadCol=%d\n",i,yyextra->blockHeadCol);
2020 if (i==yyextra->blockHeadCol || i+1==yyextra->blockHeadCol)
2021 {
2022 replaceCommentMarker(yyscanner,std::string_view(yytext,yyleng));
2023 }
2024 else
2025 {
2026 copyToOutput(yyscanner," */");
2027 for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]);
2028 yyextra->inSpecialComment=FALSE;
2029 BEGIN(Scan);
2030 }
2031 }
2032}
2033
2034/*! This function does three things:
2035 * -# It converts multi-line C++ style comment blocks (that are aligned)
2036 * to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
2037 * -# It replaces aliases with their definition (see ALIASES)
2038 * -# It handles conditional sections (cond...endcond blocks)
2039 */
2040void convertCppComments(const std::string &inBuf,std::string &outBuf,const std::string &fn)
2041{
2042 QCString fileName { fn };
2043 yyscan_t yyscanner;
2044 commentcnvYY_state extra(&inBuf,outBuf);
2045 commentcnvYYlex_init_extra(&extra,&yyscanner);
2046#ifdef FLEX_DEBUG
2047 commentcnvYYset_debug(Debug::isFlagSet(Debug::Lex_commentcnv)?1:0,yyscanner);
2048#endif
2049 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2050 //printf("convertCppComments(%s)\n",qPrint(fileName));
2051 yyextra->inBufPos = 0;
2052 yyextra->col = 0;
2053 yyextra->mlBrief = Config_getBool(MULTILINE_CPP_IS_BRIEF);
2054 yyextra->skip = FALSE;
2055 yyextra->fileName = fileName;
2056 yyextra->lang = getLanguageFromFileName(fileName);
2057 yyextra->pythonDocString = FALSE;
2058 yyextra->lineNr = 1;
2059 yyextra->raiseLevel = 0;
2060 yyextra->raiseLabel = "";
2061 yyextra->raiseIncrement = 0;
2062 yyextra->raisePrefix = "";
2063 yyextra->insertCppCommentMarker=false;
2064 yyextra->expandedAliases.clear();
2065 while (!yyextra->condStack.empty()) yyextra->condStack.pop();
2066 clearCommentStack(yyscanner);
2067 yyextra->vhdl = FALSE;
2068
2069 DebugLex debugLex(Debug::Lex_commentcnv,__FILE__, qPrint(fileName));
2070 yyextra->isFixedForm = FALSE;
2071 if (yyextra->lang==SrcLangExt::Fortran)
2072 {
2074 yyextra->isFixedForm = recognizeFixedForm(QCString(inBuf),fmt);
2075 }
2076
2077 if (yyextra->lang==SrcLangExt::Markdown)
2078 {
2079 yyextra->nestingCount=0;
2080 BEGIN(CComment);
2081 yyextra->commentStack.push(yyextra->lineNr);
2082 }
2083 else
2084 {
2085 BEGIN(Scan);
2086 }
2087 yylex(yyscanner);
2088 while (!yyextra->condStack.empty())
2089 {
2090 const commentcnvYY_CondCtx &ctx = yyextra->condStack.top();
2091 QCString sectionInfo(" ");
2092 if (ctx.sectionId!=" ") sectionInfo.sprintf(" with label '%s' ",ctx.sectionId.stripWhiteSpace().data());
2093 warn(yyextra->fileName,ctx.lineNr,"Conditional section{}does not have "
2094 "a corresponding \\endcond command within this file.",sectionInfo.data());
2095 yyextra->condStack.pop();
2096 }
2097 if (yyextra->nestingCount>0 && yyextra->lang!=SrcLangExt::Markdown && yyextra->lang!=SrcLangExt::Fortran)
2098 {
2099 QCString lines;
2100 bool first = true;
2101 while (!yyextra->commentStack.empty())
2102 {
2103 int lineNr = yyextra->commentStack.top();
2104 if (!first) lines += ", ";
2105 lines += QCString().setNum(lineNr);
2106 first = false;
2107 yyextra->commentStack.pop();
2108 }
2109 warn(yyextra->fileName,yyextra->lineNr,"Reached end of file while still inside a (nested) comment. "
2110 "Nesting level {} (possible line reference(s): {})",yyextra->nestingCount,lines);
2111 }
2112 yyextra->nestingCount = 0;
2114 {
2115 Debug::print(Debug::CommentCnv,0,"-----------\nCommentCnv: {}\n"
2116 "output=[\n{}]\n-----------\n",fileName,yyextra->outBuf
2117 );
2118 }
2119 commentcnvYYlex_destroy(yyscanner);
2120}
2121
2122
2123//----------------------------------------------------------------------------
2124
2125#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:3500
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5719
int lineBlock(const QCString &text, const QCString &marker)
Returns the line number of the line following the line with the marker.
Definition util.cpp:6384
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:6048
bool recognizeFixedForm(const QCString &contents, FortranFormat format)
Definition util.cpp:6855
QCString showFileDefMatches(const FileNameLinkedMap *fnMap, const QCString &n)
Definition util.cpp:3543
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:7130
FortranFormat convertFileNameFortranParserCode(QCString fn)
Definition util.cpp:6908
bool isId(int c)
Definition util.h:208