1 /******************************************************************************
6 * Copyright (C) 1997-2015 by Dimitri van Heesch.
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation under the terms of the GNU General Public License is hereby
10 * granted. No representations are made about the suitability of this software
11 * for any purpose. It is provided "as is" without express or implied warranty.
12 * See the GNU General Public License for more details.
14 * Documents produced by Doxygen are derivative works derived from the
15 * input used in their production; they are not affected by this license.
19 %option never-interactive
20 %option prefix="doctokenizerYY"
32 #include "doctokenizer.h"
33 #include "cmdmapper.h"
37 #include "membergroup.h"
38 #include "definition.h"
43 #define YY_NO_UNISTD_H 1
45 //--------------------------------------------------------------------------
47 // context for tokenizer phase
48 static int g_commentState;
49 TokenInfo *g_token = 0;
50 static int g_inputPos = 0;
51 static const char *g_inputString;
52 static QCString g_fileName;
53 static bool g_insidePre;
54 static int g_sharpCount=0;
56 // context for section finding phase
57 static Definition *g_definition;
58 static MemberGroup *g_memberGroup;
59 static QCString g_secLabel;
60 static QCString g_secTitle;
61 static SectionInfo::SectionType g_secType;
62 static QCString g_endMarker;
63 static int g_autoListLevel;
65 struct DocLexerContext
71 const char *inputString;
72 YY_BUFFER_STATE state;
75 static QStack<DocLexerContext> g_lexerStack;
77 //--------------------------------------------------------------------------
79 void doctokenizerYYpushContext()
81 DocLexerContext *ctx = new DocLexerContext;
83 ctx->autoListLevel = g_autoListLevel;
85 ctx->inputPos = g_inputPos;
86 ctx->inputString = g_inputString;
87 ctx->state = YY_CURRENT_BUFFER;
88 g_lexerStack.push(ctx);
89 yy_switch_to_buffer(yy_create_buffer(doctokenizerYYin, YY_BUF_SIZE));
92 bool doctokenizerYYpopContext()
94 if (g_lexerStack.isEmpty()) return FALSE;
95 DocLexerContext *ctx = g_lexerStack.pop();
96 g_autoListLevel = ctx->autoListLevel;
97 g_inputPos = ctx->inputPos;
98 g_inputString = ctx->inputString;
99 yy_delete_buffer(YY_CURRENT_BUFFER);
100 yy_switch_to_buffer(ctx->state);
107 //--------------------------------------------------------------------------
109 const char *tokToString(int token)
113 case 0: return "TK_EOF";
114 case TK_WORD: return "TK_WORD";
115 case TK_LNKWORD: return "TK_LNKWORD";
116 case TK_WHITESPACE: return "TK_WHITESPACE";
117 case TK_LISTITEM: return "TK_LISTITEM";
118 case TK_ENDLIST: return "TK_ENDLIST";
119 case TK_COMMAND: return "TK_COMMAND";
120 case TK_HTMLTAG: return "TK_HTMLTAG";
121 case TK_SYMBOL: return "TK_SYMBOL";
122 case TK_NEWPARA: return "TK_NEWPARA";
123 case TK_RCSTAG: return "TK_RCSTAG";
124 case TK_URL: return "TK_URL";
129 static int computeIndent(const char *str,int length)
133 static int tabSize=Config_getInt(TAB_SIZE);
134 for (i=0;i<length;i++)
138 indent+=tabSize - (indent%tabSize);
140 else if (str[i]=='\n')
152 //--------------------------------------------------------------------------
154 static void processSection()
156 //printf("%s: found section/anchor with name `%s'\n",g_fileName.data(),g_secLabel.data());
160 file = g_memberGroup->parent()->getOutputFileBase();
162 else if (g_definition)
164 file = g_definition->getOutputFileBase();
168 warn(g_fileName,yylineno,"Found section/anchor %s without context\n",g_secLabel.data());
171 if ((si=Doxygen::sectionDict->find(g_secLabel)))
174 si->type = g_secType;
178 static void handleHtmlTag()
180 QCString tagText=yytext;
181 g_token->attribs.clear();
182 g_token->endTag = FALSE;
183 g_token->emptyTag = FALSE;
187 if (tagText.at(1)=='/')
189 g_token->endTag = TRUE;
193 // Parse the name portion
194 int i = startNamePos;
195 for (i=startNamePos; i < (int)yyleng; i++)
197 // Check for valid HTML/XML name chars (including namespaces)
198 char c = tagText.at(i);
199 if (!(isalnum(c) || c=='-' || c=='_' || c==':')) break;
201 g_token->name = tagText.mid(startNamePos,i-startNamePos);
203 // Parse the attributes. Each attribute is a name, value pair
204 // The result is stored in g_token->attribs.
205 int startName,endName,startAttrib,endAttrib;
206 while (i<(int)yyleng)
208 char c=tagText.at(i);
210 while (i<(int)yyleng && isspace(c)) { c=tagText.at(++i); }
211 // check for end of the tag
213 // Check for XML style "empty" tag.
216 g_token->emptyTag = TRUE;
220 // search for end of name
221 while (i<(int)yyleng && !isspace(c) && c!='=') { c=tagText.at(++i); }
224 opt.name = tagText.mid(startName,endName-startName).lower();
226 while (i<(int)yyleng && isspace(c)) { c=tagText.at(++i); }
227 if (tagText.at(i)=='=') // option has value
231 while (i<(int)yyleng && isspace(c)) { c=tagText.at(++i); }
232 if (tagText.at(i)=='\'') // option '...'
237 // search for matching quote
238 while (i<(int)yyleng && c!='\'') { c=tagText.at(++i); }
240 if (i<(int)yyleng) c=tagText.at(++i);
242 else if (tagText.at(i)=='"') // option "..."
246 // search for matching quote
247 while (i<(int)yyleng && c!='"') { c=tagText.at(++i); }
249 if (i<(int)yyleng) c=tagText.at(++i);
251 else // value without any quotes
254 // search for separator or end symbol
255 while (i<(int)yyleng && !isspace(c) && c!='>') { c=tagText.at(++i); }
257 if (i<(int)yyleng) c=tagText.at(++i);
259 opt.value = tagText.mid(startAttrib,endAttrib-startAttrib);
261 else // start next option
264 //printf("=====> Adding option name=<%s> value=<%s>\n",
265 // opt.name.data(),opt.value.data());
266 g_token->attribs.append(&opt);
270 static QCString stripEmptyLines(const QCString &s)
272 if (s.isEmpty()) return QCString();
275 // skip leading empty lines
279 while ((c=s[p]) && (c==' ' || c=='\t')) p++;
289 // skip trailing empty lines
291 if (p>=start && s.at(p)=='\n') p--;
295 while ((c=s[p]) && (c==' ' || c=='\t')) p--;
306 //printf("stripEmptyLines(%d-%d)\n",start,end);
307 return s.mid(start,end-start);
310 //--------------------------------------------------------------------------
313 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
315 static int yyread(char *buf,int max_size)
318 const char *src=g_inputString+g_inputPos;
319 while ( c < max_size && *src ) *buf++ = *src++, c++;
324 //--------------------------------------------------------------------------
325 //#define REAL_YY_DECL int doctokenizerYYlex (void)
326 //#define YY_DECL static int local_doctokinizer(void)
327 //#define LOCAL_YY_DECL local_doctokinizer()
335 ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
336 LABELID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-]*
337 PHPTYPE [\\:a-z_A-Z0-9\x80-\xFF\-]+
338 CITESCHAR [a-z_A-Z0-9\x80-\xFF]
339 CITEECHAR [a-z_A-Z0-9\x80-\xFF\-\+:\/]*
340 CITEID {CITESCHAR}{CITEECHAR}*("."{CITESCHAR}{CITEECHAR}*)*
341 MAILADR ("mailto:")?[a-z_A-Z0-9.+-]+"@"[a-z_A-Z0-9-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+
342 OPTSTARS ("//"{BLANK}*)?"*"*{BLANK}*
343 LISTITEM {BLANK}*[-]("#")?{WS}
344 MLISTITEM {BLANK}*[+*]{WS}
345 OLISTITEM {BLANK}*[1-9][0-9]*"."{BLANK}
346 ENDLIST {BLANK}*"."{BLANK}*\n
347 ATTRNAME [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-]*
348 ATTRIB {ATTRNAME}{WS}*("="{WS}*(("\""[^\"]*"\"")|("'"[^\']*"'")|[^ \t\r\n'"><]+))?
349 URLCHAR [a-z_A-Z0-9\!\~\,\:\;\'\$\?\@\&\%\#\.\-\+\/\=]
350 URLMASK ({URLCHAR}+([({]{URLCHAR}*[)}])?)+
351 FILESCHAR [a-z_A-Z0-9\\:\\\/\-\+@&#]
352 FILEECHAR [a-z_A-Z0-9\-\+@&#]
353 HFILEMASK ("."{FILESCHAR}*{FILEECHAR}+)*
354 FILEMASK ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|{HFILEMASK}
355 LINKMASK [^ \t\n\r\\@<&${}]+("("[^\n)]*")")?({BLANK}*("const"|"volatile"){BLANK}+)?
356 VERBATIM "verbatim"{BLANK}*
357 SPCMD1 {CMD}([a-z_A-Z][a-z_A-Z0-9]*|{VERBATIM}|"--"|"---")
358 SPCMD2 {CMD}[\\@<>&$#%~".+|-]
359 SPCMD3 {CMD}form#[0-9]+
361 INOUT "inout"|"in"|"out"|("in"{BLANK}*","{BLANK}*"out")|("out"{BLANK}*","{BLANK}*"in")
362 PARAMIO {CMD}param{BLANK}*"["{BLANK}*{INOUT}{BLANK}*"]"
363 TEMPCHAR [a-z_A-Z0-9.,: \t\*\&\(\)\[\]]
364 FUNCCHAR [a-z_A-Z0-9,:\<\> \t\^\*\&\[\]]
365 FUNCPART {FUNCCHAR}*("("{FUNCCHAR}*")"{FUNCCHAR}*)?
366 SCOPESEP "::"|"#"|"."
367 TEMPLPART "<"{TEMPCHAR}*">"
368 ANONNS "anonymous_namespace{"[^}]*"}"
369 SCOPEPRE (({ID}{TEMPLPART}?)|{ANONNS}){SCOPESEP}
370 SCOPEKEYS ":"({ID}":")*
371 SCOPECPP {SCOPEPRE}*(~)?{ID}{TEMPLPART}?
372 SCOPEOBJC {SCOPEPRE}?{ID}{SCOPEKEYS}?
373 SCOPEMASK {SCOPECPP}|{SCOPEOBJC}
374 FUNCARG "("{FUNCPART}")"({BLANK}*("volatile"|"const"){BLANK})?
375 FUNCARG2 "("{FUNCPART}")"({BLANK}*("volatile"|"const"))?
376 OPNEW {BLANK}+"new"({BLANK}*"[]")?
377 OPDEL {BLANK}+"delete"({BLANK}*"[]")?
378 OPNORM {OPNEW}|{OPDEL}|"+"|"-"|"*"|"/"|"%"|"^"|"&"|"|"|"~"|"!"|"="|"<"|">"|"+="|"-="|"*="|"/="|"%="|"^="|"&="|"|="|"<<"|">>"|"<<="|">>="|"=="|"!="|"<="|">="|"&&"|"||"|"++"|"--"|","|"->*"|"->"|"[]"|"()"
379 OPCAST {BLANK}+[^<(\r\n.,][^(\r\n.,]*
380 OPMASK ({BLANK}*{OPNORM}{FUNCARG})
381 OPMASKOPT ({BLANK}*{OPNORM}{FUNCARG}?)|({OPCAST}{FUNCARG})
382 OPMASKOP2 ({BLANK}*{OPNORM}{FUNCARG2}?)|({OPCAST}{FUNCARG2})
383 LNKWORD1 ("::"|"#")?{SCOPEMASK}
384 CVSPEC {BLANK}*("const"|"volatile")
385 LNKWORD2 (({SCOPEPRE}*"operator"{OPMASK})|({SCOPEPRE}"operator"{OPMASKOPT})|(("::"|"#"){SCOPEPRE}*"operator"{OPMASKOPT})){CVSPEC}?
386 LNKWORD3 ([0-9a-z_A-Z\-]+("/"|"\\"))*[0-9a-z_A-Z\-]+("."[0-9a-z_A-Z]+)+
387 CHARWORDQ [^ \t\n\r\\@<>()\[\]:;\?{}&%$#,."=']
388 ESCWORD ("%"{ID}(("::"|"."){ID})*)|("%'")
389 WORD1 {ESCWORD}|{CHARWORDQ}+|"{"|"}"|"'\"'"|("\""[^"\n]*\n?[^"\n]*"\"")
390 WORD2 "."|","|"("|")"|"["|"]"|":"|";"|"\?"|"="|"'"
391 WORD1NQ {ESCWORD}|{CHARWORDQ}+|"{"|"}"
392 WORD2NQ "."|","|"("|")"|"["|"]"|":"|";"|"\?"|"="|"'"
393 CAPTION [cC][aA][pP][tT][iI][oO][nN]
394 HTMLTAG "<"(("/")?){ID}({WS}+{ATTRIB})*{WS}*(("/")?)">"
395 HTMLKEYL "strong"|"center"|"table"|"caption"|"small"|"code"|"dfn"|"var"|"img"|"pre"|"sub"|"sup"|"tr"|"td"|"th"|"ol"|"ul"|"li"|"tt"|"kbd"|"em"|"hr"|"dl"|"dt"|"dd"|"br"|"i"|"a"|"b"|"p"
396 HTMLKEYU "STRONG"|"CENTER"|"TABLE"|"CAPTION"|"SMALL"|"CODE"|"DFN"|"VAR"|"IMG"|"PRE"|"SUB"|"SUP"|"TR"|"TD"|"TH"|"OL"|"UL"|"LI"|"TT"|"KBD"|"EM"|"HR"|"DL"|"DT"|"DD"|"BR"|"I"|"A"|"B"|"P"
397 HTMLKEYW {HTMLKEYL}|{HTMLKEYU}
398 REFWORD2_PRE ("#"|"::")?((({ID}{TEMPLPART}?)|{ANONNS})("."|"#"|"::"|"-"|"/"))*({ID}{TEMPLPART}?(":")?)
399 REFWORD2 {REFWORD2_PRE}{FUNCARG2}?
400 REFWORD2_NOCV {REFWORD2_PRE}("("{FUNCPART}")")?
401 REFWORD3 ({ID}":")*{ID}":"?
402 REFWORD4_NOCV (({SCOPEPRE}*"operator"{OPMASKOP2})|(("::"|"#"){SCOPEPRE}*"operator"{OPMASKOP2}))
403 REFWORD4 {REFWORD4_NOCV}{CVSPEC}?
404 REFWORD {LABELID}|{REFWORD2}|{REFWORD3}|{REFWORD4}
405 REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
456 <St_Para>\r /* skip carriage return */
457 <St_Para>^{LISTITEM} { /* list item */
458 QCString text=yytext;
459 int dashPos = text.findRev('-');
460 g_token->isEnumList = text.at(dashPos+1)=='#';
462 g_token->indent = computeIndent(yytext,dashPos);
465 <St_Para>^{MLISTITEM} { /* list item */
466 if (!Doxygen::markdownSupport || g_insidePre)
472 QCString text=yytext;
473 static QRegExp re("[*+]");
474 int listPos = text.findRev(re);
475 g_token->isEnumList = FALSE;
477 g_token->indent = computeIndent(yytext,listPos);
481 <St_Para>^{OLISTITEM} { /* numbered list item */
482 if (!Doxygen::markdownSupport || g_insidePre)
488 QCString text=yytext;
489 static QRegExp re("[1-9]");
490 int digitPos = text.find(re);
491 int dotPos = text.find('.',digitPos);
492 g_token->isEnumList = TRUE;
493 g_token->id = atoi(QCString(yytext).mid(digitPos,dotPos-digitPos));
494 g_token->indent = computeIndent(yytext,digitPos);
498 <St_Para>{BLANK}*\n{LISTITEM} { /* list item on next line */
499 QCString text=yytext;
500 text=text.right(text.length()-text.find('\n')-1);
501 int dashPos = text.findRev('-');
502 g_token->isEnumList = text.at(dashPos+1)=='#';
504 g_token->indent = computeIndent(text,dashPos);
507 <St_Para>{BLANK}*\n{MLISTITEM} { /* list item on next line */
508 if (!Doxygen::markdownSupport || g_insidePre)
514 QCString text=yytext;
515 static QRegExp re("[*+]");
516 text=text.right(text.length()-text.find('\n')-1);
517 int markPos = text.findRev(re);
518 g_token->isEnumList = FALSE;
520 g_token->indent = computeIndent(text,markPos);
524 <St_Para>{BLANK}*\n{OLISTITEM} { /* list item on next line */
525 if (!Doxygen::markdownSupport || g_insidePre)
531 QCString text=yytext;
532 int nl=text.findRev('\n');
533 int len=text.length();
534 text=text.right(len-nl-1);
535 static QRegExp re("[1-9]");
536 int digitPos = text.find(re);
537 int dotPos = text.find('.',digitPos);
538 g_token->isEnumList = TRUE;
539 g_token->id = atoi(QCString(text).mid(digitPos,dotPos-digitPos));
540 g_token->indent = computeIndent(text,digitPos);
544 <St_Para>^{ENDLIST} { /* end list */
545 int dotPos = QCString(yytext).findRev('.');
546 g_token->indent = computeIndent(yytext,dotPos);
549 <St_Para>{BLANK}*\n{ENDLIST} { /* end list on next line */
550 QCString text=yytext;
551 text=text.right(text.length()-text.find('\n')-1);
552 int dotPos = text.findRev('.');
553 g_token->indent = computeIndent(text,dotPos);
556 <St_Para>"{"{BLANK}*"@link" {
557 g_token->name = "javalink";
560 <St_Para>"{"{BLANK}*"@inheritDoc"{BLANK}*"}" {
561 g_token->name = "inheritdoc";
564 <St_Para>"@_fakenl" { // artificial new line
568 g_token->name = "form";
570 g_token->id = QCString(yytext).right((int)yyleng-6).toInt(&ok);
574 <St_Para>{CMD}"n"\n { /* \n followed by real newline */
576 g_token->name = yytext+1;
577 g_token->name = g_token->name.stripWhiteSpace();
578 g_token->paramDir=TokenInfo::Unspecified;
583 <St_Para>{SPCMD4} { /* special command */
584 g_token->name = yytext+1;
585 g_token->name = g_token->name.stripWhiteSpace();
586 g_token->paramDir=TokenInfo::Unspecified;
589 <St_Para>{PARAMIO} { /* param [in,out] command */
590 g_token->name = "param";
592 bool isIn = s.find("in")!=-1;
593 bool isOut = s.find("out")!=-1;
598 g_token->paramDir=TokenInfo::InOut;
602 g_token->paramDir=TokenInfo::In;
607 g_token->paramDir=TokenInfo::Out;
611 g_token->paramDir=TokenInfo::Unspecified;
615 <St_Para>("http:"|"https:"|"ftp:"|"file:"|"news:"){URLMASK}/\. { // URL.
616 g_token->name=yytext;
617 g_token->isEMailAddr=FALSE;
620 <St_Para>("http:"|"https:"|"ftp:"|"file:"|"news:"){URLMASK} { // URL
621 g_token->name=yytext;
622 g_token->isEMailAddr=FALSE;
625 <St_Para>"<"("http:"|"https:"|"ftp:"|"file:"|"news:"){URLMASK}">" { // URL
626 g_token->name=yytext;
627 g_token->name = g_token->name.mid(1,g_token->name.length()-2);
628 g_token->isEMailAddr=FALSE;
631 <St_Para>{MAILADR} { // Mail address
632 g_token->name=yytext;
633 g_token->name.stripPrefix("mailto:");
634 g_token->isEMailAddr=TRUE;
637 <St_Para>"<"{MAILADR}">" { // Mail address
638 g_token->name=yytext;
639 g_token->name = g_token->name.mid(1,g_token->name.length()-2);
640 g_token->name.stripPrefix("mailto:");
641 g_token->isEMailAddr=TRUE;
644 <St_Para>"$"{ID}":"[^\n$]+"$" { /* RCS tag */
645 QCString tagName(yytext+1);
646 int index=tagName.find(':');
647 g_token->name = tagName.left(index);
648 int text_begin = index+2;
649 int text_end = tagName.length()-1;
650 if (tagName[text_begin-1]==':') /* check for Subversion fixed-length keyword */
653 if (tagName[text_end-1]=='#')
656 g_token->text = tagName.mid(text_begin,text_end-text_begin);
659 <St_Para,St_HtmlOnly>"$("{ID}")" { /* environment variable */
660 QCString name = &yytext[2];
661 name = name.left(name.length()-1);
662 QCString value = portable_getenv(name);
663 for (int i=value.length()-1;i>=0;i--) unput(value.at(i));
665 <St_Para>{HTMLTAG} { /* html tag */
669 <St_Para,St_Text>"&"{ID}";" { /* special symbol */
670 g_token->name = yytext;
674 /********* patterns for linkable words ******************/
676 <St_Para>{ID}/"<"{HTMLKEYW}">" { /* this rule is to prevent opening html
677 * tag to be recognized as a templated classes
679 g_token->name = yytext;
682 <St_Para>{LNKWORD1}/"<br>" | // prevent <br> html tag to be parsed as template arguments
683 <St_Para>{LNKWORD1} |
684 <St_Para>{LNKWORD1}{FUNCARG} |
685 <St_Para>{LNKWORD2} |
686 <St_Para>{LNKWORD3} {
687 g_token->name = yytext;
690 <St_Para>{LNKWORD1}{FUNCARG}{CVSPEC}[^a-z_A-Z0-9] {
691 g_token->name = yytext;
692 g_token->name = g_token->name.left(g_token->name.length()-1);
693 unput(yytext[(int)yyleng-1]);
696 /********* patterns for normal words ******************/
698 <St_Para,St_Text>{WORD1} |
699 <St_Para,St_Text>{WORD2} { /* function call */
700 if (yytext[0]=='%') // strip % if present
701 g_token->name = &yytext[1];
703 g_token->name = yytext;
706 /* the following is dummy code to please the
707 * compiler, removing this results in a warning
712 <St_Text>({ID}".")+{ID} {
713 g_token->name = yytext;
716 <St_Para,St_Text>"operator"/{BLANK}*"<"[a-zA-Z_0-9]+">" { // Special case: word "operator" followed by a HTML command
717 // avoid interpretation as "operator <"
718 g_token->name = yytext;
722 /*******************************************************/
724 <St_Para,St_Text>{BLANK}+ |
725 <St_Para,St_Text>{BLANK}*\n{BLANK}* { /* white space */
726 g_token->chars=yytext;
727 return TK_WHITESPACE;
729 <St_Text>[\\@<>&$#%~] {
730 g_token->name = yytext;
733 <St_Para>({BLANK}*\n)+{BLANK}*\n/{LISTITEM} { /* skip trailing paragraph followed by new list item */
734 if (g_insidePre || g_autoListLevel==0)
739 <St_Para>({BLANK}*\n)+{BLANK}*\n/{MLISTITEM} { /* skip trailing paragraph followed by new list item */
740 if (!Doxygen::markdownSupport || g_insidePre || g_autoListLevel==0)
745 <St_Para>({BLANK}*\n)+{BLANK}*\n/{OLISTITEM} { /* skip trailing paragraph followed by new list item */
746 if (!Doxygen::markdownSupport || g_insidePre || g_autoListLevel==0)
751 <St_Para>({BLANK}*\n)+{BLANK}*\n{BLANK}* {
752 g_token->indent=computeIndent(yytext,(int)yyleng);
754 // put back the indentation (needed for list items)
755 for (i=0;i<g_token->indent;i++)
759 // tell flex that after putting the last indent
760 // back we are at the beginning of the line
761 YY_CURRENT_BUFFER->yy_at_bol=1;
762 // start of a new paragraph
765 <St_CodeOpt>{BLANK}*"{"(".")?{LABELID}"}" {
766 g_token->name = yytext;
767 int i=g_token->name.find('{'); /* } to keep vi happy */
768 g_token->name = g_token->name.mid(i+1,g_token->name.length()-i-2);
776 <St_Code>{WS}*{CMD}"endcode" {
779 <St_XmlCode>{WS}*"</code>" {
782 <St_Code,St_XmlCode>[^\\@\n<]+ |
783 <St_Code,St_XmlCode>\n |
784 <St_Code,St_XmlCode>. {
785 g_token->verb+=yytext;
787 <St_HtmlOnlyOption>" [block]" { // the space is added in commentscan.l
788 g_token->name="block";
791 <St_HtmlOnlyOption>.|\n {
795 <St_HtmlOnly>{CMD}"endhtmlonly" {
798 <St_HtmlOnly>[^\\@\n$]+ |
801 g_token->verb+=yytext;
803 <St_ManOnly>{CMD}"endmanonly" {
806 <St_ManOnly>[^\\@\n$]+ |
809 g_token->verb+=yytext;
811 <St_RtfOnly>{CMD}"endrtfonly" {
814 <St_RtfOnly>[^\\@\n$]+ |
817 g_token->verb+=yytext;
819 <St_LatexOnly>{CMD}"endlatexonly" {
822 <St_LatexOnly>[^\\@\n]+ |
825 g_token->verb+=yytext;
827 <St_XmlOnly>{CMD}"endxmlonly" {
830 <St_XmlOnly>[^\\@\n]+ |
833 g_token->verb+=yytext;
835 <St_DbOnly>{CMD}"enddocbookonly" {
838 <St_DbOnly>[^\\@\n]+ |
841 g_token->verb+=yytext;
843 <St_Verbatim>{CMD}"endverbatim" {
844 g_token->verb=stripEmptyLines(g_token->verb);
847 <St_Verbatim>[^\\@\n]+ |
849 <St_Verbatim>. { /* Verbatim text */
850 g_token->verb+=yytext;
852 <St_Dot>{CMD}"enddot" {
857 <St_Dot>. { /* dot text */
858 g_token->verb+=yytext;
860 <St_Msc>{CMD}("endmsc") {
865 <St_Msc>. { /* msc text */
866 g_token->verb+=yytext;
868 <St_PlantUMLOpt>{BLANK}*"{"[^}]*"}" { // case 1: file name is specified as {filename}
869 g_token->sectionId = QCString(yytext).stripWhiteSpace();
870 // skip curly brackets around the optional image name
871 g_token->sectionId = g_token->sectionId.mid(1,g_token->sectionId.length()-2).stripWhiteSpace();
874 <St_PlantUMLOpt>{BLANK}*{FILEMASK}{BLANK}+/{ID}"=" { // case 2: plain file name specified followed by an attribute
875 g_token->sectionId = QCString(yytext).stripWhiteSpace();
878 <St_PlantUMLOpt>{BLANK}*{FILEMASK}{BLANK}+/"\"" { // case 3: plain file name specified followed by a quoted title
879 g_token->sectionId = QCString(yytext).stripWhiteSpace();
882 <St_PlantUMLOpt>{BLANK}*{FILEMASK}{BLANK}*/\n { // case 4: plain file name specified without title or attributes
883 g_token->sectionId = QCString(yytext).stripWhiteSpace();
887 g_token->sectionId = "";
891 <St_PlantUML>{CMD}"enduml" {
894 <St_PlantUML>[^\\@\n]+ |
896 <St_PlantUML>. { /* plantuml text */
897 g_token->verb+=yytext;
899 <St_Title>"\"" { // quoted title
903 g_token->chars=yytext;
904 return TK_WHITESPACE;
906 <St_Title>. { // non-quoted title
914 <St_TitleN>"&"{ID}";" { /* symbol */
915 g_token->name = yytext;
918 <St_TitleN>{HTMLTAG} {
920 <St_TitleN>{SPCMD1} |
921 <St_TitleN>{SPCMD2} { /* special command */
922 g_token->name = yytext+1;
923 g_token->paramDir=TokenInfo::Unspecified;
926 <St_TitleN>{ID}"=" { /* attribute */
927 if (yytext[0]=='%') // strip % if present
928 g_token->name = &yytext[1];
930 g_token->name = yytext;
934 <St_TitleN>{WORD2} { /* word */
935 if (yytext[0]=='%') // strip % if present
936 g_token->name = &yytext[1];
938 g_token->name = yytext;
942 g_token->chars=yytext;
943 return TK_WHITESPACE;
945 <St_TitleN>\n { /* new line => end of title */
949 <St_TitleQ>"&"{ID}";" { /* symbol */
950 g_token->name = yytext;
953 <St_TitleQ>{SPCMD1} |
954 <St_TitleQ>{SPCMD2} { /* special command */
955 g_token->name = yytext+1;
956 g_token->paramDir=TokenInfo::Unspecified;
959 <St_TitleQ>{WORD1NQ} |
960 <St_TitleQ>{WORD2NQ} { /* word */
961 g_token->name = yytext;
965 g_token->chars=yytext;
966 return TK_WHITESPACE;
968 <St_TitleQ>"\"" { /* closing quote => end of title */
972 <St_TitleQ>\n { /* new line => end of title */
976 <St_TitleA>{BLANK}*{ID}{BLANK}*"="{BLANK}* { // title attribute
977 g_token->name = yytext;
978 g_token->name = g_token->name.left(g_token->name.find('=')).stripWhiteSpace();
981 <St_TitleV>[^ \t\r\n]+ { // attribute value
982 g_token->chars = yytext;
986 <St_TitleV,St_TitleA>. {
990 <St_TitleV,St_TitleA>\n {
994 <St_Anchor>{LABELID}{WS}? { // anchor
995 g_token->name = QCString(yytext).stripWhiteSpace();
1002 <St_Cite>{CITEID} { // label to cite
1003 g_token->name=yytext;
1006 <St_Cite>{BLANK} { // white space
1010 <St_Cite>\n { // new line
1014 <St_Cite>. { // any other character
1018 <St_Ref>{REFWORD_NOCV}/{BLANK}("const")[a-z_A-Z0-9] { // see bug776988
1019 g_token->name=yytext;
1022 <St_Ref>{REFWORD_NOCV}/{BLANK}("volatile")[a-z_A-Z0-9] { // see bug776988
1023 g_token->name=yytext;
1026 <St_Ref>{REFWORD} { // label to refer to
1027 g_token->name=yytext;
1030 <St_Ref>{BLANK} { // white space
1034 <St_Ref>{WS}+"\""{WS}* { // white space following by quoted string
1037 <St_Ref>\n { // new line
1041 <St_Ref>. { // any other character
1045 <St_IntRef>[A-Z_a-z0-9.:/#\-\+\(\)]+ {
1046 g_token->name = yytext;
1049 <St_IntRef>{BLANK}+"\"" {
1052 <St_SetScope>({SCOPEMASK}|{ANONNS}){BLANK} {
1053 g_token->name = yytext;
1054 g_token->name = g_token->name.stripWhiteSpace();
1057 <St_SetScope>{SCOPEMASK}"<" {
1058 g_token->name = yytext;
1059 g_token->name = g_token->name.stripWhiteSpace();
1061 BEGIN(St_SetScopeEnd);
1063 <St_SetScope>{BLANK} {
1065 <St_SetScopeEnd>"<" {
1066 g_token->name += yytext;
1069 <St_SetScopeEnd>">" {
1070 g_token->name += yytext;
1072 if (g_sharpCount<=0)
1078 g_token->name += yytext;
1080 <St_Ref2>"&"{ID}";" { /* symbol */
1081 g_token->name = yytext;
1085 <St_Ref2>{SPCMD2} { /* special command */
1086 g_token->name = yytext+1;
1087 g_token->paramDir=TokenInfo::Unspecified;
1090 <St_Ref2>{WORD1NQ} |
1091 <St_Ref2>{WORD2NQ} {
1093 g_token->name = yytext;
1097 g_token->chars=yytext;
1098 return TK_WHITESPACE;
1100 <St_Ref2>"\""|\n { /* " or \n => end of title */
1103 <St_XRefItem>{LABELID} {
1104 g_token->name=yytext;
1107 BEGIN(St_XRefItem2);
1109 <St_XRefItem2>[0-9]+"." {
1110 QCString numStr=yytext;
1111 numStr=numStr.left((int)yyleng-1);
1112 g_token->id=numStr.toInt();
1115 <St_Para,St_Title,St_Ref2>"<!--" { /* html style comment block */
1116 g_commentState = YY_START;
1119 <St_Param>"\""[^\n\"]+"\"" {
1120 g_token->name = yytext+1;
1121 g_token->name = g_token->name.left((int)yyleng-2);
1124 <St_Param>({PHPTYPE}{BLANK}*"|"{BLANK}*)*{PHPTYPE}{WS}+("&")?"$"{LABELID} {
1125 QCString params = yytext;
1126 int j = params.find('&');
1127 int i = params.find('$');
1128 if (j<i && j!=-1) i=j;
1129 QCString types = params.left(i).stripWhiteSpace();
1130 g_token->name = types+"#"+params.mid(i);
1133 <St_Param>[^ \t\n,@\\]+ {
1134 g_token->name = yytext;
1135 if (g_token->name.at(yyleng-1)==':')
1137 g_token->name=g_token->name.left(yyleng-1);
1141 <St_Param>{WS}*","{WS}* /* param separator */
1143 g_token->chars=yytext;
1144 return TK_WHITESPACE;
1146 <St_File>{FILEMASK} {
1147 g_token->name = yytext;
1150 <St_File>"\""[^\n\"]+"\"" {
1151 QCString text=yytext;
1152 g_token->name = text.mid(1,text.length()-2);
1155 <St_Pattern>[^\r\n]+ {
1156 g_token->name = yytext;
1157 g_token->name = g_token->name.stripWhiteSpace();
1160 <St_Link>{LINKMASK}|{REFWORD} {
1161 g_token->name = yytext;
1164 <St_Comment>"-->" { /* end of html comment */
1165 BEGIN(g_commentState);
1167 <St_Comment>[^-]+ /* inside html comment */
1168 <St_Comment>. /* inside html comment */
1170 /* State for skipping title (all chars until the end of the line) */
1173 <St_SkipTitle>\n { return 0; }
1175 /* State for the pass used to find the anchors and sections */
1177 <St_Sections>[^\n@\\<]+
1178 <St_Sections>"@@"|"\\\\"|"@<"|"\\<"
1179 <St_Sections>"<"{CAPTION}({WS}+{ATTRIB})*">" {
1180 QCString tag=yytext;
1181 int s=tag.find("id=");
1182 if (s!=-1) // command has id attribute
1185 if (c=='\'' || c=='"') // valid start
1187 int e=tag.find(c,s+4);
1188 if (e!=-1) // found matching end
1190 g_secType = SectionInfo::Table;
1191 g_secLabel=tag.mid(s+4,e-s-4); // extract id
1197 <St_Sections>{CMD}"anchor"{BLANK}+ {
1198 g_secType = SectionInfo::Anchor;
1199 BEGIN(St_SecLabel1);
1201 <St_Sections>{CMD}"section"{BLANK}+ {
1202 g_secType = SectionInfo::Section;
1203 BEGIN(St_SecLabel2);
1205 <St_Sections>{CMD}"subsection"{BLANK}+ {
1206 g_secType = SectionInfo::Subsection;
1207 BEGIN(St_SecLabel2);
1209 <St_Sections>{CMD}"subsubsection"{BLANK}+ {
1210 g_secType = SectionInfo::Subsubsection;
1211 BEGIN(St_SecLabel2);
1213 <St_Sections>{CMD}"paragraph"{BLANK}+ {
1214 g_secType = SectionInfo::Paragraph;
1215 BEGIN(St_SecLabel2);
1217 <St_Sections>{CMD}"verbatim"/[^a-z_A-Z0-9] {
1218 g_endMarker="endverbatim";
1221 <St_Sections>{CMD}"dot"/[^a-z_A-Z0-9] {
1222 g_endMarker="enddot";
1225 <St_Sections>{CMD}"msc"/[^a-z_A-Z0-9] {
1226 g_endMarker="endmsc";
1229 <St_Sections>{CMD}"startuml"/[^a-z_A-Z0-9] {
1230 g_endMarker="enduml";
1233 <St_Sections>{CMD}"htmlonly"/[^a-z_A-Z0-9] {
1234 g_endMarker="endhtmlonly";
1237 <St_Sections>{CMD}"latexonly"/[^a-z_A-Z0-9] {
1238 g_endMarker="endlatexonly";
1241 <St_Sections>{CMD}"xmlonly"/[^a-z_A-Z0-9] {
1242 g_endMarker="endxmlonly";
1245 <St_Sections>{CMD}"docbookonly"/[^a-z_A-Z0-9] {
1246 g_endMarker="enddocbookonly";
1249 <St_Sections>{CMD}"code"/[^a-z_A-Z0-9] {
1250 g_endMarker="endcode";
1253 <St_Sections>"<!--" {
1257 <St_SecSkip>{CMD}{ID} {
1258 if (qstrcmp(yytext+1,g_endMarker)==0)
1264 if (qstrcmp(yytext,g_endMarker)==0)
1269 <St_SecSkip>[^a-z_A-Z0-9\-\\\@]+
1274 <St_SecLabel1>{LABELID} {
1275 g_secLabel = yytext;
1279 <St_SecLabel2>{LABELID}{BLANK}+ |
1280 <St_SecLabel2>{LABELID} {
1281 g_secLabel = yytext;
1282 g_secLabel = g_secLabel.stripWhiteSpace();
1285 <St_SecTitle>[^\n]+ |
1286 <St_SecTitle>[^\n]*\n {
1287 g_secTitle = yytext;
1288 g_secTitle = g_secTitle.stripWhiteSpace();
1292 <St_SecTitle,St_SecLabel1,St_SecLabel2>. {
1293 warn(g_fileName,yylineno,"Unexpected character `%s' while looking for section label or title",yytext);
1296 <St_Snippet>[^\n]+ |
1297 <St_Snippet>[^\n]*\n {
1298 g_token->name = yytext;
1299 g_token->name = g_token->name.stripWhiteSpace();
1303 /* Generic rules that work for all states */
1305 warn(g_fileName,yylineno,"Unexpected new line character");
1307 <*>[\\@<>&$#%~"=] { /* unescaped special character */
1308 //warn(g_fileName,yylineno,"Unexpected character `%s', assuming command \\%s was meant.",yytext,yytext);
1309 g_token->name = yytext;
1313 warn(g_fileName,yylineno,"Unexpected character `%s'",yytext);
1317 //--------------------------------------------------------------------------
1319 void doctokenizerYYFindSections(const char *input,Definition *d,
1320 MemberGroup *mg,const char *fileName)
1322 if (input==0) return;
1323 printlex(yy_flex_debug, TRUE, __FILE__, fileName);
1324 g_inputString = input;
1325 //printf("parsing --->`%s'<---\n",input);
1329 g_fileName = fileName;
1331 doctokenizerYYlineno = 1;
1332 doctokenizerYYlex();
1333 printlex(yy_flex_debug, FALSE, __FILE__, fileName);
1336 void doctokenizerYYinit(const char *input,const char *fileName)
1338 g_autoListLevel = 0;
1339 g_inputString = input;
1341 g_fileName = fileName;
1342 g_insidePre = FALSE;
1346 void doctokenizerYYsetStatePara()
1351 void doctokenizerYYsetStateTitle()
1356 void doctokenizerYYsetStateTitleAttrValue()
1361 void doctokenizerYYsetStateCode()
1368 void doctokenizerYYsetStateXmlCode()
1375 void doctokenizerYYsetStateHtmlOnly()
1379 BEGIN(St_HtmlOnlyOption);
1382 void doctokenizerYYsetStateManOnly()
1388 void doctokenizerYYsetStateRtfOnly()
1394 void doctokenizerYYsetStateXmlOnly()
1400 void doctokenizerYYsetStateDbOnly()
1406 void doctokenizerYYsetStateLatexOnly()
1409 BEGIN(St_LatexOnly);
1412 void doctokenizerYYsetStateVerbatim()
1418 void doctokenizerYYsetStateDot()
1424 void doctokenizerYYsetStateMsc()
1430 void doctokenizerYYsetStatePlantUMLOpt()
1433 g_token->sectionId="";
1434 BEGIN(St_PlantUMLOpt);
1437 void doctokenizerYYsetStatePlantUML()
1443 void doctokenizerYYsetStateParam()
1448 void doctokenizerYYsetStateXRefItem()
1453 void doctokenizerYYsetStateFile()
1458 void doctokenizerYYsetStatePattern()
1463 void doctokenizerYYsetStateLink()
1468 void doctokenizerYYsetStateCite()
1473 void doctokenizerYYsetStateRef()
1478 void doctokenizerYYsetStateInternalRef()
1483 void doctokenizerYYsetStateText()
1488 void doctokenizerYYsetStateSkipTitle()
1490 BEGIN(St_SkipTitle);
1493 void doctokenizerYYsetStateAnchor()
1498 void doctokenizerYYsetStateSnippet()
1503 void doctokenizerYYsetStateSetScope()
1508 void doctokenizerYYcleanup()
1510 yy_delete_buffer( YY_CURRENT_BUFFER );
1513 void doctokenizerYYsetInsidePre(bool b)
1518 void doctokenizerYYpushBackHtmlTag(const char *tag)
1520 QCString tagName = tag;
1521 int i,l = tagName.length();
1523 for (i=l-1;i>=0;i--)
1530 void doctokenizerYYstartAutoList()
1535 void doctokenizerYYendAutoList()
1542 // printlex(yy_flex_debug, TRUE, __FILE__, g_fileName);
1543 // int retval = LOCAL_YY_DECL;
1544 // printlex(yy_flex_debug, FALSE, __FILE__, g_fileName);
1547 #if !defined(YY_FLEX_SUBMINOR_VERSION)
1548 extern "C" { // some bogus code to keep the compiler happy
1549 void doctokenizerYYdummy() { yy_flex_realloc(0,0); }