1 /******************************************************************************
3 * Copyright (C) 1997-2020 by Dimitri van Heesch.
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.
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
15 /******************************************************************************
16 * Parser for syntax highlighting and references for XML
17 * written by Weston Thayer
18 ******************************************************************************/
20 %option never-interactive
21 %option prefix="xmlcodeYY"
23 %option extra-type="struct xmlcodeYY_state *"
24 %option noyy_top_state
29 // forward declare yyscan_t to improve type safety
30 #define YY_TYPEDEF_YY_SCANNER_T
32 typedef yyguts_t *yyscan_t;
43 #include "outputlist.h"
45 #include "membername.h"
46 #include "searchindex.h"
52 #define YY_NEVER_INTERACTIVE 1
54 #define YY_NO_UNISTD_H 1
56 struct xmlcodeYY_state
58 CodeOutputInterface * code;
59 QCString curClassName;
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;
69 bool exampleBlock = false;
80 const FileDef * sourceFileDef = 0;
81 const Definition * currentDefinition = 0;
82 const MemberDef * currentMemberDef = 0;
83 bool includeCodeFragment = false;
84 const char * currentFontClass = 0;
88 static const char *stateToString(int state);
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);
103 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
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}
117 string \"([^"&]|{esc})*\"|\'([^'&]|{esc})*\'
125 codifyLines(yyscanner,yytext);
128 endFontClass(yyscanner);
129 codify(yyscanner,yytext);
132 endFontClass(yyscanner);
133 codify(yyscanner,yytext);
136 endFontClass(yyscanner);
137 codify(yyscanner,yytext);
140 startFontClass(yyscanner,"keyword");
141 codify(yyscanner,yytext);
142 endFontClass(yyscanner);
145 startFontClass(yyscanner,"stringliteral");
146 codifyLines(yyscanner,yytext);
147 endFontClass(yyscanner);
151 // Write the < in a different color
152 char openBracket[] = { yytext[0], '\0' };
153 codify(yyscanner,openBracket);
155 // Then write the rest
157 startFontClass(yyscanner,"keywordtype");
158 codify(yyscanner,yytext);
159 endFontClass(yyscanner);
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);
169 // Then write the rest
170 yytext++; // skip the '<'
171 yytext++; // skip the '/'
172 startFontClass(yyscanner,"keywordtype");
173 codify(yyscanner,yytext);
174 endFontClass(yyscanner);
179 // Strip off the extra '!'
181 // *yytext = '<'; // replace '!' with '<'
183 startFontClass(yyscanner,"comment");
184 codifyLines(yyscanner,yytext);
185 endFontClass(yyscanner);
188 codifyLines(yyscanner,yytext);
192 //printf("!ERROR(%c)\n", *yytext);
193 codifyLines(yyscanner,yytext);
198 //----------------------------------------------------------------------------------------
200 static yy_size_t yyread(yyscan_t yyscanner,char *buf,size_t max_size)
202 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
203 yy_size_t inputPosition = yyextra->inputPosition;
204 const char *s = yyextra->inputString + inputPosition;
206 while( c < max_size && *s)
211 yyextra->inputPosition += c;
215 static void codify(yyscan_t yyscanner,const char* text)
217 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
218 yyextra->code->codify(text);
221 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
223 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
224 if (Doxygen::searchIndex)
226 if (yyextra->searchCtx)
228 yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),false);
232 yyextra->code->setCurrentDoc(yyextra->sourceFileDef,anchor,true);
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.
241 static void startCodeLine(yyscan_t yyscanner)
243 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
244 if (yyextra->sourceFileDef)
246 const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
248 if (!yyextra->includeCodeFragment && d && d->isLinkableInProject())
250 yyextra->currentDefinition = d;
251 yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
252 //yyextra->insideBody = false;
253 yyextra->classScope = d->name();
255 lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
256 if (yyextra->currentMemberDef)
258 yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
259 yyextra->currentMemberDef->getOutputFileBase(),
260 yyextra->currentMemberDef->anchor(),yyextra->yyLineNr,
261 !yyextra->includeCodeFragment);
262 setCurrentDoc(yyscanner,lineAnchor);
266 yyextra->code->writeLineNumber(d->getReference(),
267 d->getOutputFileBase(),
268 QCString(),yyextra->yyLineNr,
269 !yyextra->includeCodeFragment);
270 setCurrentDoc(yyscanner,lineAnchor);
275 yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
276 !yyextra->includeCodeFragment);
280 yyextra->code->startCodeLine(yyextra->sourceFileDef);
282 if (yyextra->currentFontClass)
284 yyextra->code->startFontClass(yyextra->currentFontClass);
288 static void endFontClass(yyscan_t yyscanner)
290 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
291 if (yyextra->currentFontClass)
293 yyextra->code->endFontClass();
294 yyextra->currentFontClass=0;
298 static void endCodeLine(yyscan_t yyscanner)
300 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
301 endFontClass(yyscanner);
302 yyextra->code->endCodeLine();
305 static void nextCodeLine(yyscan_t yyscanner)
307 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
308 const char *fc = yyextra->currentFontClass;
309 endCodeLine(yyscanner);
310 if (yyextra->yyLineNr<yyextra->inputLines)
312 yyextra->currentFontClass = fc;
313 startCodeLine(yyscanner);
317 static void codifyLines(yyscan_t yyscanner,const char *text)
319 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
320 const char *p=text,*sp=p;
326 while ((c=*p++) && c!='\n') { }
330 int l = (int)(p-sp-1);
331 char *tmp = (char*)malloc(l+1);
334 yyextra->code->codify(tmp);
336 nextCodeLine(yyscanner);
340 yyextra->code->codify(sp);
346 static void startFontClass(yyscan_t yyscanner,const char *s)
348 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
349 endFontClass(yyscanner);
350 yyextra->code->startFontClass(s);
351 yyextra->currentFontClass=s;
354 /*! counts the number of lines in the input */
355 static int countLines(yyscan_t yyscanner)
357 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
358 const char *p=yyextra->inputString;
364 if (c=='\n') count++;
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.
370 yyextra->needsTermination=true;
375 //----------------------------------------------------------------------------------------
377 struct XMLCodeParser::Private
380 xmlcodeYY_state state;
383 XMLCodeParser::XMLCodeParser() : p(std::make_unique<Private>())
385 xmlcodeYYlex_init_extra(&p->state,&p->yyscanner);
387 xmlcodeYYset_debug(1,p->yyscanner);
389 resetCodeParserState();
392 XMLCodeParser::~XMLCodeParser()
394 xmlcodeYYlex_destroy(p->yyscanner);
397 void XMLCodeParser::resetCodeParserState()
399 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
400 yyextra->currentDefinition = 0;
401 yyextra->currentMemberDef = 0;
404 void XMLCodeParser::parseCode(CodeOutputInterface &codeOutIntf,
405 const QCString &scopeName,
406 const QCString &input,
409 const QCString &exampleName,
410 const FileDef *fileDef,
414 const MemberDef *memberDef,
415 bool showLineNumbers,
416 const Definition *searchCtx,
420 yyscan_t yyscanner = p->yyscanner;
421 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
423 if (input.isEmpty()) return;
425 printlex(yy_flex_debug, true, __FILE__, fileDef ? qPrint(fileDef->fileName()): NULL);
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;
435 yyextra->yyLineNr = startLine;
437 yyextra->yyLineNr = 1;
440 yyextra->inputLines = endLine+1;
442 yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
444 yyextra->exampleBlock = isExampleBlock;
445 yyextra->exampleName = exampleName;
446 yyextra->sourceFileDef = fileDef;
448 bool cleanupSourceDef = false;
450 if (isExampleBlock && fileDef==0)
452 // create a dummy filedef for the example
453 yyextra->sourceFileDef = createFileDef("",(!exampleName.isEmpty()?exampleName:QCString("generated")));
454 cleanupSourceDef = true;
457 if (yyextra->sourceFileDef)
459 setCurrentDoc(yyscanner,"l00001");
462 yyextra->includeCodeFragment = inlineFragment;
463 // Starts line 1 on the output
464 startCodeLine(yyscanner);
466 xmlcodeYYrestart( 0, yyscanner );
468 xmlcodeYYlex(yyscanner);
470 if (yyextra->needsTermination)
472 endCodeLine(yyscanner);
474 if (cleanupSourceDef)
476 // delete the temporary file definition used for this example
477 delete yyextra->sourceFileDef;
478 yyextra->sourceFileDef=0;
481 printlex(yy_flex_debug, false, __FILE__, fileDef ? qPrint(fileDef->fileName()): NULL);
486 #include "xmlcode.l.h"