Doxygen
xmlcode.l
浏览该文件的文档.
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2020 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  * Parser for syntax highlighting and references for XML
17  * written by Weston Thayer
18  ******************************************************************************/
19 
20 %option never-interactive
21 %option prefix="xmlcodeYY"
22 %option reentrant
23 %option extra-type="struct xmlcodeYY_state *"
24 %option noyy_top_state
25 %option nounput
26 %option noyywrap
27 %top{
28 #include <stdint.h>
29 // forward declare yyscan_t to improve type safety
30 #define YY_TYPEDEF_YY_SCANNER_T
31 struct yyguts_t;
32 typedef yyguts_t *yyscan_t;
33 }
34 
35 %{
36 
37 #include <stdio.h>
38 
39 #include "xmlcode.h"
40 
41 #include "entry.h"
42 #include "doxygen.h"
43 #include "outputlist.h"
44 #include "util.h"
45 #include "membername.h"
46 #include "searchindex.h"
47 #include "config.h"
48 #include "filedef.h"
49 #include "tooltip.h"
50 #include "message.h"
51 
52 #define YY_NEVER_INTERACTIVE 1
53 #define YY_NO_INPUT 1
54 #define YY_NO_UNISTD_H 1
55 
56 struct xmlcodeYY_state
57 {
58  CodeOutputInterface * code;
59  QCString curClassName;
60  QCString parmType;
61  QCString parmName;
62  const char * inputString = 0; //!< the code fragment as text
63  yy_size_t inputPosition = 0; //!< read offset during parsing
64  int inputLines = 0; //!< number of line in the code fragment
65  int yyLineNr = 0; //!< current line number
66  bool needsTermination = false;
67  const Definition *searchCtx = 0;
68 
69  bool exampleBlock = false;
70  QCString exampleName;
71  QCString exampleFile;
72 
73  QCString type;
74  QCString name;
75  QCString args;
76  QCString classScope;
77 
78  QCString CurrScope;
79 
80  const FileDef * sourceFileDef = 0;
81  const Definition * currentDefinition = 0;
82  const MemberDef * currentMemberDef = 0;
83  bool includeCodeFragment = false;
84  const char * currentFontClass = 0;
85 };
86 
87 #if USE_STATE2STRING
88 static const char *stateToString(int state);
89 #endif
90 
91 static void codify(yyscan_t yyscanner,const char* text);
92 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor);
93 static void startCodeLine(yyscan_t yyscanner);
94 static void endFontClass(yyscan_t yyscanner);
95 static void endCodeLine(yyscan_t yyscanner);
96 static void nextCodeLine(yyscan_t yyscanner);
97 static void codifyLines(yyscan_t yyscanner,const char *text);
98 static void startFontClass(yyscan_t yyscanner,const char *s);
99 static int countLines(yyscan_t yyscanner);
100 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
101 
102 #undef YY_INPUT
103 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
104 
105 %}
106 
107 nl (\r\n|\r|\n)
108 ws [ \t]+
109 open "<"
110 close ">"
111 namestart [A-Za-z\200-\377_]
112 namechar [:A-Za-z\200-\377_0-9.-]
113 esc "&#"[0-9]+";"|"&#x"[0-9a-fA-F]+";"
114 name {namestart}{namechar}*
115 comment {open}"!--"([^-]|"-"[^-])*"--"{close}
116 data "random string"
117 string \"([^"&]|{esc})*\"|\'([^'&]|{esc})*\'
118 
119 %option noyywrap
120 %option nounput
121 
122 %%
123 
124 <INITIAL>{ws} {
125  codifyLines(yyscanner,yytext);
126  }
127 <INITIAL>"/" {
128  endFontClass(yyscanner);
129  codify(yyscanner,yytext);
130  }
131 <INITIAL>"=" {
132  endFontClass(yyscanner);
133  codify(yyscanner,yytext);
134  }
135 <INITIAL>{close} {
136  endFontClass(yyscanner);
137  codify(yyscanner,yytext);
138  }
139 <INITIAL>{name} {
140  startFontClass(yyscanner,"keyword");
141  codify(yyscanner,yytext);
142  endFontClass(yyscanner);
143  }
144 <INITIAL>{string} {
145  startFontClass(yyscanner,"stringliteral");
146  codifyLines(yyscanner,yytext);
147  endFontClass(yyscanner);
148  }
149 
150 {open}{ws}?{name} {
151  // Write the < in a different color
152  char openBracket[] = { yytext[0], '\0' };
153  codify(yyscanner,openBracket);
154 
155  // Then write the rest
156  yytext++;
157  startFontClass(yyscanner,"keywordtype");
158  codify(yyscanner,yytext);
159  endFontClass(yyscanner);
160 
161  BEGIN(INITIAL);
162  }
163 {open}{ws}?"/"{name} {
164  // Write the "</" in a different color
165  char closeBracket[] = { yytext[0], yytext[1], '\0' };
166  endFontClass(yyscanner);
167  codify(yyscanner,closeBracket);
168 
169  // Then write the rest
170  yytext++; // skip the '<'
171  yytext++; // skip the '/'
172  startFontClass(yyscanner,"keywordtype");
173  codify(yyscanner,yytext);
174  endFontClass(yyscanner);
175 
176  BEGIN(INITIAL);
177  }
178 {comment} {
179  // Strip off the extra '!'
180  // yytext++; // <
181  // *yytext = '<'; // replace '!' with '<'
182 
183  startFontClass(yyscanner,"comment");
184  codifyLines(yyscanner,yytext);
185  endFontClass(yyscanner);
186  }
187 {nl} {
188  codifyLines(yyscanner,yytext);
189  }
190 
191 . {
192  //printf("!ERROR(%c)\n", *yytext);
193  codifyLines(yyscanner,yytext);
194  }
195 
196 %%
197 
198 //----------------------------------------------------------------------------------------
199 
200 static yy_size_t yyread(yyscan_t yyscanner,char *buf,size_t max_size)
201 {
202  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
203  yy_size_t inputPosition = yyextra->inputPosition;
204  const char *s = yyextra->inputString + inputPosition;
205  yy_size_t c=0;
206  while( c < max_size && *s)
207  {
208  *buf++ = *s++;
209  c++;
210  }
211  yyextra->inputPosition += c;
212  return c;
213 }
214 
215 static void codify(yyscan_t yyscanner,const char* text)
216 {
217  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
218  yyextra->code->codify(text);
219 }
220 
221 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
222 {
223  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
224  if (Doxygen::searchIndex)
225  {
226  if (yyextra->searchCtx)
227  {
228  yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),false);
229  }
230  else
231  {
232  yyextra->code->setCurrentDoc(yyextra->sourceFileDef,anchor,true);
233  }
234  }
235 }
236 
237 /*! start a new line of code, inserting a line number if yyextra->sourceFileDef
238  * is true. If a definition starts at the current line, then the line
239  * number is linked to the documentation of that definition.
240  */
241 static void startCodeLine(yyscan_t yyscanner)
242 {
243  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
244  if (yyextra->sourceFileDef)
245  {
246  const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
247 
248  if (!yyextra->includeCodeFragment && d && d->isLinkableInProject())
249  {
250  yyextra->currentDefinition = d;
251  yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
252  //yyextra->insideBody = false;
253  yyextra->classScope = d->name();
254  QCString lineAnchor;
255  lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
256  if (yyextra->currentMemberDef)
257  {
258  yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
259  yyextra->currentMemberDef->getOutputFileBase(),
260  yyextra->currentMemberDef->anchor(),yyextra->yyLineNr,
261  !yyextra->includeCodeFragment);
262  setCurrentDoc(yyscanner,lineAnchor);
263  }
264  else
265  {
266  yyextra->code->writeLineNumber(d->getReference(),
267  d->getOutputFileBase(),
268  QCString(),yyextra->yyLineNr,
269  !yyextra->includeCodeFragment);
270  setCurrentDoc(yyscanner,lineAnchor);
271  }
272  }
273  else
274  {
275  yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
276  !yyextra->includeCodeFragment);
277  }
278  }
279 
280  yyextra->code->startCodeLine(yyextra->sourceFileDef);
281 
282  if (yyextra->currentFontClass)
283  {
284  yyextra->code->startFontClass(yyextra->currentFontClass);
285  }
286 }
287 
288 static void endFontClass(yyscan_t yyscanner)
289 {
290  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
291  if (yyextra->currentFontClass)
292  {
293  yyextra->code->endFontClass();
294  yyextra->currentFontClass=0;
295  }
296 }
297 
298 static void endCodeLine(yyscan_t yyscanner)
299 {
300  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
301  endFontClass(yyscanner);
302  yyextra->code->endCodeLine();
303 }
304 
305 static void nextCodeLine(yyscan_t yyscanner)
306 {
307  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
308  const char *fc = yyextra->currentFontClass;
309  endCodeLine(yyscanner);
310  if (yyextra->yyLineNr<yyextra->inputLines)
311  {
312  yyextra->currentFontClass = fc;
313  startCodeLine(yyscanner);
314  }
315 }
316 
317 static void codifyLines(yyscan_t yyscanner,const char *text)
318 {
319  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
320  const char *p=text,*sp=p;
321  char c;
322  bool done=false;
323  while (!done)
324  {
325  sp=p;
326  while ((c=*p++) && c!='\n') { }
327  if (c=='\n')
328  {
329  yyextra->yyLineNr++;
330  int l = (int)(p-sp-1);
331  char *tmp = (char*)malloc(l+1);
332  strncpy(tmp,sp,l);
333  tmp[l]='\0';
334  yyextra->code->codify(tmp);
335  free(tmp);
336  nextCodeLine(yyscanner);
337  }
338  else
339  {
340  yyextra->code->codify(sp);
341  done=true;
342  }
343  }
344 }
345 
346 static void startFontClass(yyscan_t yyscanner,const char *s)
347 {
348  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
349  endFontClass(yyscanner);
350  yyextra->code->startFontClass(s);
351  yyextra->currentFontClass=s;
352 }
353 
354 /*! counts the number of lines in the input */
355 static int countLines(yyscan_t yyscanner)
356 {
357  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
358  const char *p=yyextra->inputString;
359  char c;
360  int count=1;
361  while ((c=*p))
362  {
363  p++ ;
364  if (c=='\n') count++;
365  }
366  if (p>yyextra->inputString && *(p-1)!='\n')
367  { // last line does not end with a \n, so we add an extra
368  // line and explicitly terminate the line after parsing.
369  count++,
370  yyextra->needsTermination=true;
371  }
372  return count;
373 }
374 
375 //----------------------------------------------------------------------------------------
376 
377 struct XMLCodeParser::Private
378 {
379  yyscan_t yyscanner;
380  xmlcodeYY_state state;
381 };
382 
383 XMLCodeParser::XMLCodeParser() : p(std::make_unique<Private>())
384 {
385  xmlcodeYYlex_init_extra(&p->state,&p->yyscanner);
386 #ifdef FLEX_DEBUG
387  xmlcodeYYset_debug(1,p->yyscanner);
388 #endif
389  resetCodeParserState();
390 }
391 
392 XMLCodeParser::~XMLCodeParser()
393 {
394  xmlcodeYYlex_destroy(p->yyscanner);
395 }
396 
397 void XMLCodeParser::resetCodeParserState()
398 {
399  struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
400  yyextra->currentDefinition = 0;
401  yyextra->currentMemberDef = 0;
402 }
403 
404 void XMLCodeParser::parseCode(CodeOutputInterface &codeOutIntf,
405  const QCString &scopeName,
406  const QCString &input,
407  SrcLangExt,
408  bool isExampleBlock,
409  const QCString &exampleName,
410  const FileDef *fileDef,
411  int startLine,
412  int endLine,
413  bool inlineFragment,
414  const MemberDef *memberDef,
415  bool showLineNumbers,
416  const Definition *searchCtx,
417  bool collectXRefs
418  )
419 {
420  yyscan_t yyscanner = p->yyscanner;
421  struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
422 
423  if (input.isEmpty()) return;
424 
425  printlex(yy_flex_debug, true, __FILE__, fileDef ? qPrint(fileDef->fileName()): NULL);
426 
427  yyextra->code = &codeOutIntf;
428  yyextra->inputString = input.data();
429  yyextra->inputPosition = 0;
430  yyextra->currentFontClass = 0;
431  yyextra->needsTermination = false;
432  yyextra->searchCtx = searchCtx;
433 
434  if (startLine!=-1)
435  yyextra->yyLineNr = startLine;
436  else
437  yyextra->yyLineNr = 1;
438 
439  if (endLine!=-1)
440  yyextra->inputLines = endLine+1;
441  else
442  yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
443 
444  yyextra->exampleBlock = isExampleBlock;
445  yyextra->exampleName = exampleName;
446  yyextra->sourceFileDef = fileDef;
447 
448  bool cleanupSourceDef = false;
449 
450  if (isExampleBlock && fileDef==0)
451  {
452  // create a dummy filedef for the example
453  yyextra->sourceFileDef = createFileDef("",(!exampleName.isEmpty()?exampleName:QCString("generated")));
454  cleanupSourceDef = true;
455  }
456 
457  if (yyextra->sourceFileDef)
458  {
459  setCurrentDoc(yyscanner,"l00001");
460  }
461 
462  yyextra->includeCodeFragment = inlineFragment;
463  // Starts line 1 on the output
464  startCodeLine(yyscanner);
465 
466  xmlcodeYYrestart( 0, yyscanner );
467 
468  xmlcodeYYlex(yyscanner);
469 
470  if (yyextra->needsTermination)
471  {
472  endCodeLine(yyscanner);
473  }
474  if (cleanupSourceDef)
475  {
476  // delete the temporary file definition used for this example
477  delete yyextra->sourceFileDef;
478  yyextra->sourceFileDef=0;
479  }
480 
481  printlex(yy_flex_debug, false, __FILE__, fileDef ? qPrint(fileDef->fileName()): NULL);
482 }
483 
484 
485 #if USE_STATE2STRING
486 #include "xmlcode.l.h"
487 #endif