Doxygen
lexcode.l
浏览该文件的文档.
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2021 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 %option never-interactive
17 %option prefix="lexcodeYY"
18 %option noyywrap
19 %option reentrant
20 %option extra-type="struct lexcodeYY_state *"
21 %top{
22 #include <stdint.h>
23 // forward declare yyscan_t to improve type safety
24 #define YY_TYPEDEF_YY_SCANNER_T
25 struct yyguts_t;
26 typedef yyguts_t *yyscan_t;
27 }
28 
29 %{
30 
31 #include <stdio.h>
32 
33 #include "config.h"
34 #include "doxygen.h"
35 #include "outputgen.h"
36 #include "code.h"
37 #include "lexcode.h"
38 #include "filedef.h"
39 #include "message.h"
40 
41 #define YY_NEVER_INTERACTIVE 1
42 #define YY_NO_INPUT 1
43 #define YY_NO_UNISTD_H 1
44 
45 #define USE_STATE2STRING 0
46 
47 struct lexcodeYY_state
48 {
49  CodeOutputInterface * code;
50  CCodeParser ccodeParser;
51  const char *inputString; //!< the code fragment as text
52  yy_size_t inputPosition; //!< read offset during parsing
53  int inputLines; //!< number of line in the code fragment
54  int yyLineNr; //!< current line number
55  bool needsTermination;
56 
57  bool lineNumbers = FALSE;
58  const Definition *searchCtx;
59  bool collectXRefs = FALSE;
60 
61  int lastContext = 0;
62  int lastCContext = 0;
63  int lastStringContext = 0;
64  int docBlockContext = 0;
65  int lastPreLineCtrlContext = 0;
66  int lastRawStringContext = 0;
67  int curlyCount = 0;
68 
69  QCString rulesPatternBuffer;
70  QCString CCodeBuffer;
71  int startCCodeLine = -1;
72  int roundCount = 0;
73  bool insideCode = FALSE;
74  QCString delimiter;
75  QCString docBlockName;
76  uint fencedSize = 0;
77  bool nestedComment = false;
78 
79  bool exampleBlock;
80  QCString exampleName;
81  QCString classScope;
82 
83  const FileDef *sourceFileDef;
84  const Definition *currentDefinition;
85  const MemberDef *currentMemberDef;
86  bool includeCodeFragment;
87  const char *currentFontClass;
88 };
89 
90 #if USE_STATE2STRING
91 static const char *stateToString(int state);
92 #endif
93 
94 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor);
95 static void startCodeLine(yyscan_t yyscanner);
96 static void endFontClass(yyscan_t yyscanner);
97 static void endCodeLine(yyscan_t yyscanner);
98 static void nextCodeLine(yyscan_t yyscanner);
99 static void codifyLines(yyscan_t yyscanner,const QCString &text);
100 static void startFontClass(yyscan_t yyscanner,const char *s);
101 static int countLines(yyscan_t yyscanner);
102 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
103 static void lineCount(yyscan_t yyscanner);
104 static void handleCCode(yyscan_t yyscanner);
105 
106 #undef YY_INPUT
107 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
108 
109 %}
110 
111 nl (\r\n|\r|\n)
112 ws [ \t]
113 nws [^ \t\n]
114 TopStart "%top{"{nl}
115 TopEnd "}"{nl}
116 LiteralStart "%{"{nl}
117 LiteralEnd "%}"{nl}
118 RulesStart "%%"{nl}
119 RulesEnd "%%"{nl}
120 RulesSharp "<"[^>\n]*">"
121 RulesCurly "{"[^{}\n]*"}"
122 StartSquare "["
123 StartDouble "\""
124 StartRound "("
125 StartRoundQuest "(?"
126 EscapeRulesCharOpen "\\["|"\<"|"\\{"|"\\("|"\\\""|"\\ "|"\\\\"
127 EscapeRulesCharClose "\\]"|"\>"|"\\}"|"\\)"
128 EscapeRulesChar {EscapeRulesCharOpen}|{EscapeRulesCharClose}
129 
130 CMD ("\\"|"@")
131 BN [ \t\n\r]
132 BL [ \t\r]*"\n"
133 B [ \t]
134 Bopt {B}*
135 ID [$a-z_A-Z\x80-\xFF][$a-z_A-Z0-9\x80-\xFF]*
136 PRE [pP][rR][eE]
137 CODE [cC][oO][dD][eE]
138 RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
139 RAWEND ")"[^ \t\(\)\\]{0,16}\"
140 CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
141 CHARCE "[:"[^:]*":]"
142 
143  /* no comment start / end signs inside square brackets */
144 NCOMM [^/\*]
145  // C start comment
146 CCS "/\*"
147  // C end comment
148 CCE "*\/"
149  // Cpp comment
150 CPPC "/\/"
151  // doxygen start comment
152 DCOMM ("/\*!"|"/\**"|"/\/!"|"/\/\/")
153 
154  // Optional any character
155 ANYopt .*
156  // Optional all but newline
157 NONLopt [^\n]*
158 
159 %x DefSection
160 %x DefSectionLine
161 %x RulesSectionInit
162 %x RulesPattern
163 %x RulesDouble
164 %x RulesRoundDouble
165 %x RulesSquare
166 %x RulesRoundSquare
167 %x RulesRound
168 %x RulesRoundQuest
169 %x UserSection
170 
171 %x TopSection
172 %x LiteralSection
173 
174 %x COMMENT
175 
176 %x SkipCurly
177 %x SkipCurlyEndDoc
178 %x PreLineCtrl
179 %x DocLine
180 %x DocBlock
181 %x DocCopyBlock
182 %x SkipString
183 %x RawString
184 %x SkipComment
185 %x SkipCxxComment
186 %x Comment
187 
188 %%
189 
190 <*>\x0d
191 <DefSection>^{TopStart} {
192  handleCCode(yyscanner);
193  codifyLines(yyscanner,yytext);
194  yyextra->lastContext = YY_START;
195  yyextra->startCCodeLine=yyextra->yyLineNr;
196  BEGIN (TopSection);
197  }
198 <DefSection>^{LiteralStart} {
199  handleCCode(yyscanner);
200  codifyLines(yyscanner,yytext);
201  yyextra->lastContext = YY_START;
202  yyextra->startCCodeLine=yyextra->yyLineNr;
203  BEGIN (LiteralSection);
204  }
205 <TopSection>^{TopEnd} {
206  handleCCode(yyscanner);
207  codifyLines(yyscanner,yytext);
208  BEGIN( yyextra->lastContext ) ;
209  }
210 <TopSection>.*{nl} {
211  yyextra->CCodeBuffer += yytext;
212  yyextra->yyLineNr++;
213  }
214 <LiteralSection>^{LiteralEnd} {
215  handleCCode(yyscanner);
216  codifyLines(yyscanner,yytext);
217  BEGIN( yyextra->lastContext ) ;
218  }
219 <LiteralSection>.*{nl} {
220  yyextra->CCodeBuffer += yytext;
221  yyextra->yyLineNr++;
222  }
223 <DefSection>{CPPC}.*{nl} {
224  yyextra->CCodeBuffer += yytext;
225  yyextra->yyLineNr++;
226  }
227 <DefSection>^{ws}*{CCS} {
228  yyextra->CCodeBuffer += yytext;
229  yyextra->lastContext = YY_START;
230  BEGIN(COMMENT);
231  }
232 <COMMENT>{CCE}{ws}*{nl} {
233  yyextra->CCodeBuffer+=yytext;
234  yyextra->yyLineNr++;
235  handleCCode(yyscanner);
236  BEGIN(yyextra->lastContext);
237  }
238 <COMMENT>{CCE} {
239  yyextra->CCodeBuffer+=yytext;
240  handleCCode(yyscanner);
241  BEGIN(yyextra->lastContext);
242  }
243 <COMMENT>[^*\n]+ {
244  yyextra->CCodeBuffer += yytext;
245  }
246 <COMMENT>{CPPC}|{CCS} {
247  yyextra->CCodeBuffer += yytext;
248  }
249 <COMMENT>{nl} {
250  yyextra->CCodeBuffer += yytext;
251  yyextra->yyLineNr++;
252  }
253 <COMMENT>. {
254  yyextra->CCodeBuffer += yytext;
255  }
256 <DefSection>^{nl} {
257  handleCCode(yyscanner);
258  codifyLines(yyscanner,yytext);
259  yyextra->startCCodeLine=yyextra->yyLineNr;
260  }
261 <DefSection>^{ws}.*{nl} {
262  yyextra->CCodeBuffer += yytext;
263  yyextra->yyLineNr++;
264  }
265 <DefSection>^{RulesStart} {
266  handleCCode(yyscanner);
267  codifyLines(yyscanner,yytext);
268  yyextra->startCCodeLine=yyextra->yyLineNr;
269  BEGIN (RulesSectionInit);
270  }
271 <DefSection>^{nws} {
272  handleCCode(yyscanner);
273  codifyLines(yyscanner,yytext);
274  BEGIN(DefSectionLine);
275  }
276 <DefSectionLine>.*{nl} {
277  codifyLines(yyscanner,yytext);
278  yyextra->startCCodeLine=yyextra->yyLineNr;
279  BEGIN(DefSection);
280  }
281 <RulesSectionInit,RulesPattern>^{RulesEnd} {
282  handleCCode(yyscanner);
283  codifyLines(yyscanner,yytext);
284  yyextra->startCCodeLine=yyextra->yyLineNr;
285  BEGIN (UserSection);
286  }
287 <RulesSectionInit>^{nws} {
288  handleCCode(yyscanner);
289  unput(*yytext);
290  BEGIN(RulesPattern);
291  }
292 <RulesSectionInit>{nl} {
293  yyextra->CCodeBuffer += yytext;
294  yyextra->yyLineNr++;
295  }
296 <RulesSectionInit>^{ws}.*{nl} {
297  yyextra->CCodeBuffer += yytext;
298  yyextra->yyLineNr++;
299  }
300 <RulesPattern>"<<EOF>>" {
301  yyextra->rulesPatternBuffer += yytext;
302  }
303 <RulesPattern>{EscapeRulesChar} {
304  yyextra->rulesPatternBuffer += yytext;
305  }
306 <RulesPattern>{RulesSharp} {
307  yyextra->rulesPatternBuffer += yytext;
308  }
309 <RulesPattern>{RulesCurly} {
310  yyextra->rulesPatternBuffer += yytext;
311  }
312 <RulesPattern>{StartDouble} {
313  yyextra->rulesPatternBuffer += yytext;
314  yyextra->lastContext = YY_START;
315  BEGIN(RulesDouble);
316  }
317 <RulesDouble,RulesRoundDouble>"\\\\" {
318  yyextra->rulesPatternBuffer += yytext;
319  }
320 <RulesDouble,RulesRoundDouble>"\\\"" {
321  yyextra->rulesPatternBuffer += yytext;
322  }
323 <RulesDouble>"\"" {
324  yyextra->rulesPatternBuffer += yytext;
325  BEGIN( yyextra->lastContext ) ;
326  }
327 <RulesRoundDouble>"\"" {
328  yyextra->rulesPatternBuffer += yytext;
329  BEGIN(RulesRound) ;
330  }
331 <RulesDouble,RulesRoundDouble>. {
332  yyextra->rulesPatternBuffer += yytext;
333  }
334 <RulesPattern>{StartSquare} {
335  yyextra->rulesPatternBuffer += yytext;
336  yyextra->lastContext = YY_START;
337  BEGIN(RulesSquare);
338  }
339 <RulesSquare,RulesRoundSquare>{CHARCE} {
340  yyextra->rulesPatternBuffer += yytext;
341  }
342 <RulesSquare,RulesRoundSquare>"\\[" |
343 <RulesSquare,RulesRoundSquare>"\\]" {
344  yyextra->rulesPatternBuffer += yytext;
345  }
346 <RulesSquare>"]" {
347  yyextra->rulesPatternBuffer += yytext;
348  BEGIN(RulesPattern) ;
349  }
350 <RulesRoundSquare>"]" {
351  yyextra->rulesPatternBuffer += yytext;
352  BEGIN(RulesRound) ;
353  }
354 <RulesSquare,RulesRoundSquare>"\\\\" {
355  yyextra->rulesPatternBuffer += yytext;
356  }
357 <RulesSquare,RulesRoundSquare>. {
358  yyextra->rulesPatternBuffer += yytext;
359  }
360 <RulesPattern>{StartRoundQuest} {
361  yyextra->rulesPatternBuffer += yytext;
362  yyextra->lastContext = YY_START;
363  BEGIN(RulesRoundQuest);
364  }
365 <RulesRoundQuest>{nl} {
366  yyextra->rulesPatternBuffer += yytext;
367  if (!yyextra->rulesPatternBuffer.isEmpty())
368  {
369  startFontClass(yyscanner,"stringliteral");
370  codifyLines(yyscanner,yyextra->rulesPatternBuffer.data());
371  yyextra->rulesPatternBuffer.resize(0);
372  endFontClass(yyscanner);
373  }
374  }
375 <RulesRoundQuest>[^)] {
376  yyextra->rulesPatternBuffer += yytext;
377  }
378 <RulesRoundQuest>")" {
379  yyextra->rulesPatternBuffer += yytext;
380  BEGIN(yyextra->lastContext);
381  }
382 <RulesPattern>{StartRound} {
383  yyextra->roundCount++;
384  yyextra->rulesPatternBuffer += yytext;
385  yyextra->lastContext = YY_START;
386  BEGIN(RulesRound);
387  }
388 <RulesRound>{RulesCurly} {
389  yyextra->rulesPatternBuffer += yytext;
390  }
391 <RulesRound>{StartSquare} {
392  yyextra->rulesPatternBuffer += yytext;
393  BEGIN(RulesRoundSquare);
394  }
395 <RulesRound>{StartDouble} {
396  yyextra->rulesPatternBuffer += yytext;
397  BEGIN(RulesRoundDouble);
398  }
399 <RulesRound>{EscapeRulesChar} {
400  yyextra->rulesPatternBuffer += yytext;
401  }
402 <RulesRound>"(" {
403  yyextra->roundCount++;
404  yyextra->rulesPatternBuffer += yytext;
405  }
406 <RulesRound>")" {
407  yyextra->roundCount--;
408  yyextra->rulesPatternBuffer += yytext;
409  if (!yyextra->roundCount) BEGIN( yyextra->lastContext ) ;
410  }
411 <RulesRound>{nl} {
412  yyextra->rulesPatternBuffer += yytext;
413  yyextra->yyLineNr++;
414  }
415 <RulesRound>{ws} {
416  yyextra->rulesPatternBuffer += yytext;
417  }
418 <RulesRound>. {
419  yyextra->rulesPatternBuffer += yytext;
420  }
421 <RulesPattern>{ws}+"|" {
422  if (!yyextra->rulesPatternBuffer.isEmpty())
423  {
424  startFontClass(yyscanner,"stringliteral");
425  codifyLines(yyscanner,yyextra->rulesPatternBuffer);
426  yyextra->rulesPatternBuffer.resize(0);
427  endFontClass(yyscanner);
428  }
429  codifyLines(yyscanner,yytext);
430  yyextra->startCCodeLine=yyextra->yyLineNr;
431  yyextra->curlyCount = 0;
432  BEGIN(SkipCurly);
433  }
434 <RulesPattern>^{ws}*{nl} {
435  codifyLines(yyscanner,"\n");
436  }
437 <RulesPattern>^{ws}+ {
438  codifyLines(yyscanner,yytext);
439  }
440 <RulesPattern>({ws}|{nl}) {
441  unput(*yytext);
442  if (!yyextra->rulesPatternBuffer.isEmpty())
443  {
444  startFontClass(yyscanner,"stringliteral");
445  codifyLines(yyscanner,yyextra->rulesPatternBuffer);
446  yyextra->rulesPatternBuffer.resize(0);
447  endFontClass(yyscanner);
448  }
449  yyextra->startCCodeLine=yyextra->yyLineNr;
450  yyextra->curlyCount = 0;
451  BEGIN(SkipCurly);
452  }
453 <RulesPattern>"\\\\" {
454  yyextra->rulesPatternBuffer += yytext;
455  }
456 <RulesPattern>{CCS} {
457  if (!yyextra->rulesPatternBuffer.isEmpty())
458  {
459  startFontClass(yyscanner,"stringliteral");
460  codifyLines(yyscanner,yyextra->rulesPatternBuffer);
461  yyextra->rulesPatternBuffer.resize(0);
462  endFontClass(yyscanner);
463  }
464  yyextra->CCodeBuffer += yytext;
465  yyextra->lastContext = YY_START;
466  BEGIN(COMMENT);
467  }
468 <RulesPattern>. {
469  yyextra->rulesPatternBuffer += yytext;
470  }
471 <SkipCurly>{B}*"#"{B}+[0-9]+{B}+/"\"" { /* line control directive */
472  yyextra->CCodeBuffer += yytext;
473  yyextra->lastPreLineCtrlContext = YY_START;
474  BEGIN( PreLineCtrl );
475  }
476 <PreLineCtrl>"\""[^\n\"]*"\"" {
477  yyextra->CCodeBuffer += yytext;
478  }
479 <PreLineCtrl>. {
480  yyextra->CCodeBuffer += yytext;
481  }
482 <PreLineCtrl>\n {
483  yyextra->CCodeBuffer += yytext;
484  yyextra->yyLineNr++;
485  BEGIN( yyextra->lastPreLineCtrlContext );
486  }
487 <SkipCurly>"{" {
488  yyextra->CCodeBuffer += yytext;
489  ++yyextra->curlyCount ;
490  }
491 <SkipCurly>"}"/{BN}*{DCOMM}"<!--" | /* see bug710917 */
492 <SkipCurly>"}" {
493  yyextra->CCodeBuffer += yytext;
494  lineCount(yyscanner);
495  if( yyextra->curlyCount )
496  {
497  --yyextra->curlyCount ;
498  }
499  }
500 <SkipCurly>"}"{BN}*{DCOMM}"<" {
501  yyextra->CCodeBuffer += yytext;
502  lineCount(yyscanner);
503  if ( yyextra->curlyCount )
504  {
505  --yyextra->curlyCount ;
506  }
507  else
508  {
509  yyextra->docBlockContext = SkipCurlyEndDoc;
510  if (yytext[yyleng-3]=='/')
511  {
512  BEGIN( DocLine );
513  }
514  else
515  {
516  BEGIN( DocBlock );
517  }
518  }
519  }
520 <SkipCurly>\" {
521  yyextra->CCodeBuffer += yytext;
522  yyextra->lastStringContext=SkipCurly;
523  BEGIN( SkipString );
524  }
525 <SkipCurly>^{B}*"#" {
526  yyextra->CCodeBuffer += yytext;
527  yyextra->lastPreLineCtrlContext = YY_START;
528  BEGIN( PreLineCtrl );
529  }
530 <SkipCurly>{B}*{RAWBEGIN} {
531  QCString raw=QCString(yytext).stripWhiteSpace();
532  yyextra->delimiter = raw.mid(2);
533  yyextra->delimiter=yyextra->delimiter.left(yyextra->delimiter.length()-1);
534  yyextra->lastRawStringContext = YY_START;
535  yyextra->CCodeBuffer += yytext;
536  BEGIN(RawString);
537  }
538 <SkipCurly>[^\n#"'@\\/{}<]+ {
539  yyextra->CCodeBuffer += yytext;
540  }
541 <SkipCurly>{CCS} {
542  yyextra->CCodeBuffer += yytext;
543  yyextra->lastCContext = YY_START;
544  BEGIN(SkipComment);
545  }
546 <SkipCurly>{CPPC} {
547  yyextra->CCodeBuffer += yytext;
548  yyextra->lastCContext = YY_START;
549  BEGIN(SkipCxxComment);
550  }
551 <SkipCurly>{CHARLIT} {
552  yyextra->CCodeBuffer += yytext;
553  }
554 <SkipCurly>\' {
555  yyextra->CCodeBuffer += yytext;
556  }
557 <SkipCurly>. {
558  yyextra->CCodeBuffer += yytext;
559  }
560 <SkipCurly>({CPPC}{B}*)?{CCS}"!" {
561  yyextra->CCodeBuffer += yytext;
562  yyextra->docBlockContext = YY_START;
563  BEGIN( DocBlock );
564  }
565 <SkipCurly>{CCS}"*"[*]+{BL} {
566  bool javadocBanner = Config_getBool(JAVADOC_BANNER);
567  yyextra->CCodeBuffer += yytext;
568  yyextra->yyLineNr++;
569  if( javadocBanner )
570  {
571  yyextra->docBlockContext = YY_START;
572  BEGIN( DocBlock );
573  }
574  else
575  {
576  BEGIN( Comment ) ;
577  }
578  }
579 <SkipCurly>({CPPC}{B}*)?{CCS}"*"/{NCOMM} {
580  yyextra->CCodeBuffer += yytext;
581  yyextra->docBlockContext = YY_START;
582  BEGIN( DocBlock );
583  }
584 <SkipCurly>{CPPC}"!" {
585  yyextra->CCodeBuffer += yytext;
586  yyextra->docBlockContext = YY_START;
587  BEGIN( DocLine );
588  }
589 <SkipCurly>{CPPC}"/"/[^/] {
590  yyextra->CCodeBuffer += yytext;
591  yyextra->docBlockContext = YY_START;
592  BEGIN( DocLine );
593  }
594 
595 <SkipCurly>\n {
596  yyextra->CCodeBuffer += yytext;
597  yyextra->yyLineNr++;
598  if (yyextra->curlyCount<=0)
599  {
600  handleCCode(yyscanner);
601  BEGIN(RulesPattern);
602  }
603  }
604 <SkipString>\\. {
605  yyextra->CCodeBuffer += yytext;
606  }
607 <SkipString>\" {
608  yyextra->CCodeBuffer += yytext;
609  BEGIN( yyextra->lastStringContext );
610  }
611 <SkipString>{CCS}|{CCE}|{CPPC} {
612  yyextra->CCodeBuffer += yytext;
613  }
614 <SkipString>\n {
615  yyextra->CCodeBuffer += yytext;
616  yyextra->yyLineNr++;
617  }
618 <SkipString>. {
619  yyextra->CCodeBuffer += yytext;
620  }
621 <SkipCxxComment>.*"\\\n" { // line continuation
622  yyextra->CCodeBuffer += yytext;
623  yyextra->yyLineNr++;
624  }
625 <SkipCxxComment>{ANYopt}/\n {
626  yyextra->CCodeBuffer += yytext;
627  BEGIN( yyextra->lastCContext ) ;
628  }
629 <Comment>{BN}+ {
630  yyextra->CCodeBuffer += yytext ;
631  lineCount(yyscanner);
632  }
633 <Comment>{CCS} { yyextra->CCodeBuffer += yytext ; }
634 <Comment>{CPPC} { yyextra->CCodeBuffer += yytext ; }
635 <Comment>{CMD}("code"|"verbatim") {
636  yyextra->insideCode=TRUE;
637  yyextra->CCodeBuffer += yytext ;
638  }
639 <Comment>{CMD}("endcode"|"endverbatim") {
640  yyextra->insideCode=FALSE;
641  yyextra->CCodeBuffer += yytext ;
642  }
643 <Comment>[^ \.\t\r\n\/\*]+ { yyextra->CCodeBuffer += yytext ; }
644 <Comment>{CCE} {
645  yyextra->CCodeBuffer += yytext ;
646  if (!yyextra->insideCode) BEGIN( yyextra->lastContext ) ;
647  }
648 <Comment>. { yyextra->CCodeBuffer += *yytext ; }
649 
650 <SkipComment>{CPPC}|{CCS} {
651  yyextra->CCodeBuffer += yytext;
652  }
653 <SkipComment>[^\*\n]+ {
654  yyextra->CCodeBuffer += yytext;
655  }
656 <SkipComment>\n {
657  yyextra->CCodeBuffer += yytext;
658  yyextra->yyLineNr++;
659  }
660 <SkipComment>{B}*{CCE} {
661  yyextra->CCodeBuffer += yytext;
662  BEGIN( yyextra->lastCContext );
663  }
664 <SkipComment>"*" {
665  yyextra->CCodeBuffer += yytext;
666  }
667 <RawString>{RAWEND} {
668  yyextra->CCodeBuffer += yytext;
669  QCString delimiter = yytext+1;
670  delimiter=delimiter.left(delimiter.length()-1);
671  if (delimiter==yyextra->delimiter)
672  {
673  BEGIN(yyextra->lastRawStringContext);
674  }
675  }
676 <RawString>[^)\n]+ {
677  yyextra->CCodeBuffer += yytext;
678  }
679 <RawString>. {
680  yyextra->CCodeBuffer += yytext;
681  }
682 <RawString>\n {
683  yyextra->CCodeBuffer += yytext;
684  yyextra->yyLineNr++;
685  }
686 
687 
688  /* ---- Single line comments ------ */
689 <DocLine>[^\n]*"\n"[ \t]*{CPPC}[/!][<]? { // continuation of multiline C++-style comment
690  yyextra->CCodeBuffer += yytext;
691  lineCount(yyscanner);
692  }
693 <DocLine>{B}*{CPPC}"/"[/]+{Bopt}/"\n" { // ignore marker line (see bug700345)
694  yyextra->CCodeBuffer += yytext;
695  BEGIN( yyextra->docBlockContext );
696  }
697 <DocLine>{NONLopt}/"\n"{B}*{CPPC}[!/]{B}*{CMD}"}" { // next line is an end group marker, see bug 752712
698  yyextra->CCodeBuffer += yytext;
699  BEGIN( yyextra->docBlockContext );
700  }
701 <DocLine>{NONLopt}/"\n" { // whole line
702  yyextra->CCodeBuffer += yytext;
703  BEGIN( yyextra->docBlockContext );
704  }
705 
706  /* ---- Comments blocks ------ */
707 
708 <DocBlock>"*"*{CCE} { // end of comment block
709  yyextra->CCodeBuffer += yytext;
710  BEGIN(yyextra->docBlockContext);
711  }
712 <DocBlock>^{B}*"*"+/[^/] {
713  yyextra->CCodeBuffer += yytext;
714  }
715 <DocBlock>^{B}*({CPPC})?{B}*"*"+/[^/a-z_A-Z0-9*] { // start of a comment line
716  yyextra->CCodeBuffer += yytext;
717  }
718 <DocBlock>^{B}*({CPPC}){B}* { // strip embedded C++ comments if at the start of a line
719  yyextra->CCodeBuffer += yytext;
720  }
721 <DocBlock>{CPPC} { // slashes in the middle of a comment block
722  yyextra->CCodeBuffer += yytext;
723  }
724 <DocBlock>{CCS} { // start of a new comment in the
725  // middle of a comment block
726  yyextra->CCodeBuffer += yytext;
727  }
728 <DocBlock>({CMD}{CMD}){ID}/[^a-z_A-Z0-9] { // escaped command
729  yyextra->CCodeBuffer += yytext;
730  }
731 <DocBlock>{CMD}("f$"|"f["|"f{"|"f(") {
732  yyextra->CCodeBuffer += yytext;
733  yyextra->docBlockName=&yytext[1];
734  if (yyextra->docBlockName.at(1)=='[')
735  {
736  yyextra->docBlockName.at(1)=']';
737  }
738  if (yyextra->docBlockName.at(1)=='{')
739  {
740  yyextra->docBlockName.at(1)='}';
741  }
742  if (yyextra->docBlockName.at(1)=='(')
743  {
744  yyextra->docBlockName.at(1)=')';
745  }
746  yyextra->fencedSize=0;
747  yyextra->nestedComment=FALSE;
748  BEGIN(DocCopyBlock);
749  }
750 <DocBlock>{B}*"<"{PRE}">" {
751  yyextra->CCodeBuffer += yytext;
752  yyextra->docBlockName="<pre>";
753  yyextra->fencedSize=0;
754  yyextra->nestedComment=FALSE;
755  BEGIN(DocCopyBlock);
756  }
757 <DocBlock>{CMD}"startuml"/[^a-z_A-Z0-9\-] { // verbatim type command (which could contain nested comments!)
758  yyextra->CCodeBuffer += yytext;
759  yyextra->docBlockName="uml";
760  yyextra->fencedSize=0;
761  yyextra->nestedComment=FALSE;
762  BEGIN(DocCopyBlock);
763  }
764 <DocBlock>{CMD}("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"manonly"|"rtfonly"|"docbookonly"|"dot"|"msc"|"code")/[^a-z_A-Z0-9\-] { // verbatim command (which could contain nested comments!)
765  yyextra->CCodeBuffer += yytext;
766  yyextra->docBlockName=&yytext[1];
767  yyextra->fencedSize=0;
768  yyextra->nestedComment=FALSE;
769  BEGIN(DocCopyBlock);
770  }
771 <DocBlock>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
772  yyextra->CCodeBuffer += yytext;
773  QCString pat = substitute(yytext,"*"," ");
774  yyextra->docBlockName="~~~";
775  yyextra->fencedSize=pat.stripWhiteSpace().length();
776  yyextra->nestedComment=FALSE;
777  BEGIN(DocCopyBlock);
778  }
779 <DocBlock>^({B}*"*"+)?{B}{0,3}"```"[`]* {
780  yyextra->CCodeBuffer += yytext;
781  QCString pat = substitute(yytext,"*"," ");
782  yyextra->docBlockName="```";
783  yyextra->fencedSize=pat.stripWhiteSpace().length();
784  yyextra->nestedComment=FALSE;
785  BEGIN(DocCopyBlock);
786  }
787 <DocBlock>{B}*"<code>" {
788  REJECT;
789  }
790 <DocBlock>[^@*~\/\\\n]+ { // any character that isn't special
791  yyextra->CCodeBuffer += yytext;
792  }
793 <DocBlock>\n { // newline
794  yyextra->CCodeBuffer += yytext;
795  lineCount(yyscanner);
796  }
797 <DocBlock>. { // command block
798  yyextra->CCodeBuffer += yytext;
799  }
800  /* ---- Copy verbatim sections ------ */
801 
802 <DocCopyBlock>"</"{PRE}">" { // end of a <pre> block
803  yyextra->CCodeBuffer += yytext;
804  if (yyextra->docBlockName=="<pre>")
805  {
806  BEGIN(DocBlock);
807  }
808  }
809 <DocCopyBlock>"</"{CODE}">" { // end of a <code> block
810  yyextra->CCodeBuffer += yytext;
811  if (yyextra->docBlockName=="<code>")
812  {
813  BEGIN(DocBlock);
814  }
815  }
816 <DocCopyBlock>[\\@]("f$"|"f]"|"f}"|"f)") {
817  yyextra->CCodeBuffer += yytext;
818  if (yyextra->docBlockName==&yytext[1])
819  {
820  BEGIN(DocBlock);
821  }
822  }
823 <DocCopyBlock>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endmanonly"|"endrtfonly"|"enddot"|"endmsc"|"enduml"|"endcode")/[^a-z_A-Z0-9] { // end of verbatim block
824  yyextra->CCodeBuffer += yytext;
825  if (&yytext[4]==yyextra->docBlockName)
826  {
827  BEGIN(DocBlock);
828  }
829  }
830 <DocCopyBlock>^{B}*"*"+/{BN}+ { // start of a comment line
831  yyextra->CCodeBuffer += yytext;
832  if (yyextra->docBlockName=="verbatim")
833  {
834  REJECT;
835  }
836  else if (yyextra->docBlockName=="code")
837  {
838  REJECT;
839  }
840  else
841  {
842  yyextra->CCodeBuffer += yytext;
843  }
844  }
845 <DocCopyBlock>^{B}*"*"+/{B}+"*"{BN}* { // start of a comment line with two *'s
846  if (yyextra->docBlockName=="code")
847  {
848  yyextra->CCodeBuffer += yytext;
849  }
850  else
851  {
852  REJECT;
853  }
854  }
855 <DocCopyBlock>^{B}*"*"+/({ID}|"(") { // Assume *var or *(... is part of source code (see bug723516)
856  if (yyextra->docBlockName=="code")
857  {
858  yyextra->CCodeBuffer += yytext;
859  }
860  else
861  {
862  REJECT;
863  }
864  }
865 <DocCopyBlock>^{B}*"*"+/{BN}* { // start of a comment line with one *
866  if (yyextra->docBlockName=="code")
867  {
868  if (yyextra->nestedComment) // keep * it is part of the code
869  {
870  yyextra->CCodeBuffer += yytext;
871  }
872  else // remove * it is part of the comment block
873  {
874  yyextra->CCodeBuffer += yytext;
875  }
876  }
877  else
878  {
879  REJECT;
880  }
881  }
882 <DocCopyBlock>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
883  yyextra->CCodeBuffer += yytext;
884  QCString pat = substitute(yytext,"*"," ");
885  if (yyextra->fencedSize==pat.stripWhiteSpace().length())
886  {
887  BEGIN(DocBlock);
888  }
889  }
890 <DocCopyBlock>^({B}*"*"+)?{B}{0,3}"```"[`]* {
891  yyextra->CCodeBuffer += yytext;
892  QCString pat = substitute(yytext,"*"," ");
893  if (yyextra->fencedSize==pat.stripWhiteSpace().length())
894  {
895  BEGIN(DocBlock);
896  }
897  }
898 <DocCopyBlock>[^<@/\*\]~\$\\\n]+ { // any character that is not special
899  yyextra->CCodeBuffer += yytext;
900  }
901 <DocCopyBlock>{CCS}|{CCE}|{CPPC} {
902  if (yytext[1]=='*')
903  {
904  yyextra->nestedComment=TRUE;
905  }
906  else if (yytext[0]=='*')
907  {
908  yyextra->nestedComment=FALSE;
909  }
910  yyextra->CCodeBuffer += yytext;
911  }
912 <DocCopyBlock>\n { // newline
913  yyextra->CCodeBuffer += yytext;
914  lineCount(yyscanner);
915  }
916 <DocCopyBlock>. { // any other character
917  yyextra->CCodeBuffer += yytext;
918  }
919 <SkipCurlyEndDoc>"}"{BN}*{DCOMM}"<" { // desc is followed by another one
920  yyextra->docBlockContext = SkipCurlyEndDoc;
921  yyextra->CCodeBuffer += yytext;
922  if (yytext[yyleng-3]=='/')
923  {
924  BEGIN( DocLine );
925  }
926  else
927  {
928  BEGIN( DocBlock );
929  }
930  }
931 <SkipCurlyEndDoc>"}" {
932  yyextra->CCodeBuffer += yytext;
933  BEGIN(SkipCurly);
934  }
935 
936 <UserSection>.*{nl} {
937  yyextra->CCodeBuffer += yytext;
938  yyextra->yyLineNr++;
939  }
940  /*
941 <*>. { fprintf(stderr,"Lex code scanner Def rule for %s: #%s#\n",stateToString(YY_START),yytext);}
942 <*>{nl} { fprintf(stderr,"Lex code scanner Def rule for newline %s: #%s#\n",stateToString(YY_START),yytext); yyextra->yyLineNr++;}
943  */
944 <*><<EOF>> {
945  handleCCode(yyscanner);
946  yyterminate();
947  }
948 %%
949 
950 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
951 {
952  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
953  if (Doxygen::searchIndex)
954  {
955  if (yyextra->searchCtx)
956  {
957  yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),false);
958  }
959  else
960  {
961  yyextra->code->setCurrentDoc(yyextra->sourceFileDef,anchor,true);
962  }
963  }
964 }
965 
966 /*! start a new line of code, inserting a line number if yyextra->sourceFileDef
967  * is true. If a definition starts at the current line, then the line
968  * number is linked to the documentation of that definition.
969  */
970 static void startCodeLine(yyscan_t yyscanner)
971 {
972  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
973  if (yyextra->sourceFileDef && yyextra->lineNumbers)
974  {
975  const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
976 
977  if (!yyextra->includeCodeFragment && d)
978  {
979  yyextra->currentDefinition = d;
980  yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
981  yyextra->classScope = d->name();
982  QCString lineAnchor;
983  lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
984  if (yyextra->currentMemberDef)
985  {
986  yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
987  yyextra->currentMemberDef->getOutputFileBase(),
988  yyextra->currentMemberDef->anchor(),yyextra->yyLineNr,
989  !yyextra->includeCodeFragment);
990  setCurrentDoc(yyscanner,lineAnchor);
991  }
992  else
993  {
994  yyextra->code->writeLineNumber(d->getReference(),
995  d->getOutputFileBase(),
996  QCString(),yyextra->yyLineNr,
997  !yyextra->includeCodeFragment);
998  setCurrentDoc(yyscanner,lineAnchor);
999  }
1000  }
1001  else
1002  {
1003  yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
1004  !yyextra->includeCodeFragment);
1005  }
1006  }
1007 
1008  yyextra->code->startCodeLine(yyextra->sourceFileDef && yyextra->lineNumbers);
1009 
1010  if (yyextra->currentFontClass)
1011  {
1012  yyextra->code->startFontClass(yyextra->currentFontClass);
1013  }
1014 }
1015 
1016 static void endFontClass(yyscan_t yyscanner)
1017 {
1018  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1019  if (yyextra->currentFontClass)
1020  {
1021  yyextra->code->endFontClass();
1022  yyextra->currentFontClass=0;
1023  }
1024 }
1025 
1026 static void endCodeLine(yyscan_t yyscanner)
1027 {
1028  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1029  endFontClass(yyscanner);
1030  yyextra->code->endCodeLine();
1031 }
1032 
1033 static void nextCodeLine(yyscan_t yyscanner)
1034 {
1035  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1036  const char *fc = yyextra->currentFontClass;
1037  endCodeLine(yyscanner);
1038  if (yyextra->yyLineNr<yyextra->inputLines)
1039  {
1040  yyextra->currentFontClass = fc;
1041  startCodeLine(yyscanner);
1042  }
1043 }
1044 
1045 static void codifyLines(yyscan_t yyscanner,const QCString &text)
1046 {
1047  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1048  if (text.isEmpty()) return;
1049  const char *p=text.data(),*sp=p;
1050  char c;
1051  bool done=false;
1052  while (!done)
1053  {
1054  sp=p;
1055  while ((c=*p++) && c!='\n') { }
1056  if (c=='\n')
1057  {
1058  yyextra->yyLineNr++;
1059  int l = (int)(p-sp-1);
1060  char *tmp = (char*)malloc(l+1);
1061  memcpy(tmp,sp,l);
1062  tmp[l]='\0';
1063  yyextra->code->codify(tmp);
1064  nextCodeLine(yyscanner);
1065  free(tmp);
1066  }
1067  else
1068  {
1069  yyextra->code->codify(sp);
1070  done=true;
1071  }
1072  }
1073  yyextra->startCCodeLine = yyextra->yyLineNr;
1074 }
1075 
1076 static void startFontClass(yyscan_t yyscanner,const char *s)
1077 {
1078  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1079  endFontClass(yyscanner);
1080  if (!yyextra->currentFontClass || !s || strcmp(yyextra->currentFontClass,s))
1081  {
1082  endFontClass(yyscanner);
1083  yyextra->code->startFontClass(s);
1084  yyextra->currentFontClass=s;
1085  }
1086 }
1087 
1088 /*! counts the number of lines in the input */
1089 static int countLines(yyscan_t yyscanner)
1090 {
1091  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1092  const char *p=yyextra->inputString;
1093  char c;
1094  int count=1;
1095  while ((c=*p))
1096  {
1097  p++ ;
1098  if (c=='\n') count++;
1099  }
1100  if (p>yyextra->inputString && *(p-1)!='\n')
1101  { // last line does not end with a \n, so we add an extra
1102  // line and explicitly terminate the line after parsing.
1103  count++,
1104  yyextra->needsTermination=true;
1105  }
1106  return count;
1107 }
1108 
1109 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
1110 {
1111  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1112  yy_size_t inputPosition = yyextra->inputPosition;
1113  const char *s = yyextra->inputString + inputPosition;
1114  yy_size_t c=0;
1115  while( c < max_size && *s )
1116  {
1117  *buf++ = *s++;
1118  c++;
1119  }
1120  yyextra->inputPosition += c;
1121  return c;
1122 }
1123 
1124 static void lineCount(yyscan_t yyscanner)
1125 {
1126  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1127  const char *p;
1128  for (p = yytext ; *p ; ++p )
1129  {
1130  if (*p=='\n')
1131  {
1132  yyextra->yyLineNr++;
1133  }
1134  }
1135 }
1136 
1137 static void handleCCode(yyscan_t yyscanner)
1138 {
1139  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1140  if (yyextra->CCodeBuffer.isEmpty()) return;
1141 
1142  yyextra->ccodeParser.setStartCodeLine(false);
1143  yyextra->ccodeParser.parseCode(*yyextra->code,
1144  yyextra->classScope,
1145  yyextra->CCodeBuffer,
1146  SrcLangExt_Cpp,
1147  yyextra->exampleBlock,
1148  yyextra->exampleName,
1149  yyextra->sourceFileDef,
1150  yyextra->startCCodeLine,
1151  -1, /* endLine will be calculated in called routine */
1152  yyextra->includeCodeFragment,
1153  yyextra->currentMemberDef,
1154  yyextra->lineNumbers,
1155  yyextra->searchCtx,
1156  yyextra->collectXRefs
1157  );
1158  yyextra->CCodeBuffer.resize(0);
1159  yyextra->ccodeParser.setStartCodeLine(true);
1160  yyextra->yyLineNr--;
1161  codifyLines(yyscanner,"\n");
1162  return;
1163 }
1164 
1165 // public interface -----------------------------------------------------------
1166 
1167 struct LexCodeParser::Private
1168 {
1169  yyscan_t yyscanner;
1170  lexcodeYY_state state;
1171 };
1172 
1173 LexCodeParser::LexCodeParser() : p(std::make_unique<Private>())
1174 {
1175  lexcodeYYlex_init_extra(&p->state, &p->yyscanner);
1176 #ifdef FLEX_DEBUG
1177  lexcodeYYset_debug(1,p->yyscanner);
1178 #endif
1179  resetCodeParserState();
1180 }
1181 
1182 LexCodeParser::~LexCodeParser()
1183 {
1184  lexcodeYYlex_destroy(p->yyscanner);
1185 }
1186 
1187 void LexCodeParser::resetCodeParserState()
1188 {
1189  struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
1190  yyextra->currentDefinition = 0;
1191  yyextra->currentMemberDef = 0;
1192 }
1193 
1194 void LexCodeParser::parseCode(CodeOutputInterface &codeOutIntf,
1195  const QCString &scopeName,
1196  const QCString &input,
1197  SrcLangExt,
1198  bool isExampleBlock,
1199  const QCString &exampleName,
1200  const FileDef *fileDef,
1201  int startLine,
1202  int endLine,
1203  bool inlineFragment,
1204  const MemberDef *memberDef,
1205  bool showLineNumbers,
1206  const Definition *searchCtx,
1207  bool collectXRefs
1208  )
1209 {
1210  yyscan_t yyscanner = p->yyscanner;
1211  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1212 
1213  if (input.isEmpty()) return;
1214 
1215  printlex(yy_flex_debug, true, __FILE__, fileDef ? qPrint(fileDef->fileName()): NULL);
1216 
1217  yyextra->code = &codeOutIntf;
1218  yyextra->inputString = input.data();
1219  yyextra->inputPosition = 0;
1220  yyextra->currentFontClass = 0;
1221  yyextra->needsTermination = false;
1222 
1223  yyextra->classScope=scopeName;
1224  yyextra->currentMemberDef=memberDef;
1225  yyextra->searchCtx=searchCtx;
1226  yyextra->collectXRefs=collectXRefs;
1227 
1228  if (startLine!=-1)
1229  yyextra->yyLineNr = startLine;
1230  else
1231  yyextra->yyLineNr = 1;
1232 
1233  if (endLine!=-1)
1234  yyextra->inputLines = endLine+1;
1235  else
1236  yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
1237 
1238  yyextra->startCCodeLine = yyextra->yyLineNr;
1239  yyextra->exampleBlock = isExampleBlock;
1240  yyextra->exampleName = exampleName;
1241  yyextra->sourceFileDef = fileDef;
1242  yyextra->lineNumbers = fileDef!=0 && showLineNumbers;
1243 
1244  bool cleanupSourceDef = false;
1245 
1246  if (isExampleBlock && fileDef==0)
1247  {
1248  // create a dummy filedef for the example
1249  yyextra->sourceFileDef = createFileDef(QCString(),!exampleName.isEmpty() ? exampleName : QCString("generated"));
1250  cleanupSourceDef = true;
1251  }
1252 
1253  if (yyextra->sourceFileDef)
1254  {
1255  setCurrentDoc(yyscanner,"l00001");
1256  }
1257 
1258  yyextra->includeCodeFragment = inlineFragment;
1259  // Starts line 1 on the output
1260  startCodeLine(yyscanner);
1261 
1262  lexcodeYYrestart( 0, yyscanner );
1263  BEGIN( DefSection );
1264  lexcodeYYlex(yyscanner);
1265 
1266  if (yyextra->needsTermination)
1267  {
1268  endCodeLine(yyscanner);
1269  }
1270  if (cleanupSourceDef)
1271  {
1272  // delete the temporary file definition used for this example
1273  delete yyextra->sourceFileDef;
1274  yyextra->sourceFileDef=0;
1275  }
1276 
1277  printlex(yy_flex_debug, false, __FILE__, fileDef ? qPrint(fileDef->fileName()): NULL);
1278 }
1279 
1280 //---------------------------------------------------------------------------------
1281 
1282 #if USE_STATE2STRING
1283 #include "lexcode.l.h"
1284 #endif