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 vhdl subset
18 * supports VHDL-87/93/2008
19 ******************************************************************************/
20 %option never-interactive
21 %option case-insensitive
22 %option prefix="vhdlcodeYY"
24 %option extra-type="struct vhdlcodeYY_state *"
27 // forward declare yyscan_t to improve type safety
28 #define YY_TYPEDEF_YY_SCANNER_T
30 typedef yyguts_t *yyscan_t;
35 #include <unordered_set>
49 #include "outputlist.h"
51 #include "membername.h"
52 #include "searchindex.h"
53 #include "vhdldocgen.h"
54 #include "arguments.h"
62 #define YY_NO_UNISTD_H 1
64 #define USE_STATE2STRING 0
66 // Toggle for some debugging info
67 //#define DBG_CTX(x) fprintf x
68 #define DBG_CTX(x) do { } while(0)
71 /* -----------------------------------------------------------------
75 // ----------------- <vhdl> ----------------------------------
77 struct vhdlcodeYY_state
79 bool isFuncProto = false;
80 bool isComponent = false;
81 bool isPackageBody = false;
83 bool startCode = false;
86 std::unordered_set<std::string> vhdlKeyDict;
89 const MemberDef * vhdlMember = 0;
92 CodeOutputInterface * code = 0;
93 const char * inputString = 0; //!< the code fragment as text
94 yy_size_t inputPosition = 0; //!< read offset during parsing
95 int inputLines = 0; //!< number of line in the code fragment
96 int yyLineNr = 0; //!< current line number
97 bool needsTermination = false;
98 const Definition *searchCtx = 0;
100 bool exampleBlock = false;
101 QCString exampleName;
102 QCString exampleFile;
104 bool currArch = false;
106 const FileDef * sourceFileDef = 0;
107 const Definition * currentDefinition = 0;
108 const MemberDef * currentMemberDef = 0;
109 bool includeCodeFragment = false;
110 const char * currentFontClass = 0;
112 bool lexInit = false;
114 TooltipManager tooltipManager;
118 static void writeFont(yyscan_t yyscanner,const char *s,const QCString &text);
119 static void generateMemLink(yyscan_t yyscanner,CodeOutputInterface &ol,QCString &clName,QCString& memberName);
120 static bool writeColoredWord(yyscan_t yyscanner,QCString& word );
121 static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol,const QCString &clName, bool typeOnly=false, const QCString &curr_class=QCString());
122 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor);
123 static bool checkVhdlString(yyscan_t yyscanner,QCString &name);
124 static void addToSearchIndex(yyscan_t yyscanner,const QCString &text);
125 static void startCodeLine(yyscan_t yyscanner);
126 static void endCodeLine(yyscan_t yyscanner);
127 static void nextCodeLine(yyscan_t yyscanner);
128 static void writeWord(yyscan_t yyscanner,const QCString &word,const QCString &curr_class=QCString(),bool classLink=false);
129 static void codifyLines(yyscan_t yyscanner,const QCString &text,const QCString &cl=QCString(),bool classlink=false,bool comment=false);
130 static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol,
132 const QCString &text);
133 static void generateFuncLink(yyscan_t yyscanner,CodeOutputInterface &ol,const MemberDef* mdef);
134 static int countLines(yyscan_t yyscanner);
135 static void endFontClass(yyscan_t yyscanner);
136 static void startFontClass(yyscan_t yyscanner,const char *s);
137 static void appStringLower(QCString& qcs,const char* text);
138 static void codifyMapLines(yyscan_t yyscanner,const QCString &text);
139 static void writeFuncProto(yyscan_t yyscanner);
140 static void writeProcessProto(yyscan_t yyscanner);
141 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
144 static const char *stateToString(int state);
146 //-------------------------------------------------------------------
150 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
158 NAME [a-z_A-Z][ a-z_A-Z0-9]*
159 FUNCNAME [a-z_A-Z"][a-z_A-Z0-9+*"/=<>-]*
160 ID "$"?[a-z_A-Z][a-z_A-Z0-9]*
161 SPECSIGN [:;, +*&\/=<>'\t]*
162 DIGITSS [0-9]+|[0-9]+("#")*[0-9_a-fA-F\+\.\-]+("#")*
163 ALLTYPESMAP {B}*[_a-zA-Z0-9. ]+{BN}*
164 ALLTYPESMAP1 {BN}*[_a-zA-Z0-9.() ]+{BN}*
166 ARCHITECTURE ^{B}*("architecture"){BN}+{FUNCNAME}{BN}+("of"){BN}+{FUNCNAME}{BN}+("is")
167 PROCESS ({BN}*{FUNCNAME}{BN}*[:]+{BN}*("process"){BN}*[(]*)|[^a-zA-Z]("process "|"process("){BN}*[ (]*|[^a-zA-Z]("process"){BN}+
169 END1 {B}*("end "){BN}+("if"|"case"|"loop"|"generate"|"for")
170 END2 [^a-zA-Z_]("end"){BN}*[;]
171 END3 {BN}*[^a-zA-Z]("end"){BN}+{FUNCNAME}{BN}*[;]
172 END4 {B}*("end"){BN}+"function"{BN}+{FUNCNAME}{BN}*[;]
173 ENDEFUNC {END3}|{END4}|{END2}
175 KEYWORD ("of"|"new"|"event"|"break"|"case"|"end"|"loop"|"else"|"for"|"goto"|"if"|"return"|"generate"|"is"|"while"|"in")
176 TYPEKW ^{B}*("type"|"subtype"|"constant"|"attribute"|"signal"|"variable","alias","configuration")
177 FUNC ^{B}*("function"|"procedure"){BN}*{FUNCNAME}{BN}*("(")
179 ARITHOP "+"|"-"|"/"|"*"|"%"|"/="|":="
180 ASSIGNOP "="|"*="|"/="|"%="|"+="|"-="|"<<="|">>="|"&="|"^="|"|="
181 LOGICOP "=="|"!="|">"|"<"|">="|"<="|"&&"|"||"|"!"
182 BITOP "&"|"|"|"^"|"<<"|">>"|"~"
183 OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}
185 PORT {B}*("port"){BN}*("(")
186 GENERIC {B}*("generic"){BN}*("(")
193 MAPCOMPONENT1 ({ALLTYPESMAP}[:]{ALLTYPESMAP}{TEXTT}*{BN}+("port"|"generic"){BN}+("map"){BN}*("("){1})
194 MAPCOMPONENT2 {BN}*("port"|"generic"){BN}+("map"){BN}*("("){1}
195 MAPCOMPONENT3 ({ALLTYPESMAP}[:]{BN}*{ALLTYPESMAP1}{TEXTT}*{BN}+("port"|"generic"){BN}+("map"){BN}*("("){1})
196 MAPCOMPONENT4 ({ALLTYPESMAP}[:]{BN}*("entity"|"component"|"configuration"){BN}+{ALLTYPESMAP1}{TEXTT}*{BN}*("port"|"generic"){BN}*("map"){BN}*("("){1})
198 XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFIG"|"CONFIG_MODE"|"COOL_CLK"|"DATA_GATE"|"DCI_VALUE"|"DISABLE"|"DRIVE"|"DROP_SPEC"|"ENABLE"|"FAST"|"FEEDBACK"|"FILE"|"FLOAT"|"FROM-THRU-TO"|"FROM-TO"|"HBLKNM"|"HU_SET"|"INREG"|"IOB"|"IOBDELAY"|"IOSTANDARD"|"KEEP"|"KEEPER"|"LOC"|"LOCATE"|"LOCK_PINS"|"MAP"|"MAXDELAY"|"MAXPT"|"MAXSKEW"|"NODELAY"|"NOREDUCE"|"OFFSET"|"OPEN_DRAIN"|"OPT_EFFORT"|"OPTIMIZE"|"PERIOD"|"PIN"|"PRIORITY"|"PROHIBIT"|"PULLDOWN"|"PULLUP"|"PWR_MODE"|"REG"|"RLOC"|"RLOC_ORIGIN"|"RLOC_RANGE"|"SAVE NET"|"FLAG"|"SYSTEM_JITTER"|"TEMPERATURE"|"TIMEGRP"|"TIMESPEC"|"VOLTAGE"
220 yyextra->braceCount++;
221 writeFont(yyscanner,"vhdlchar",yytext);
225 <Map>[^()\n,--]* { /* write and link a port map lines */
227 VhdlDocGen::deleteAllChars(tt,',');
228 auto ql = split(tt.str(),"=>");
231 unsigned int index=0;
233 char cc=t1.at(index);
234 while (cc==' ' || cc=='\t')
239 yyextra->code->codify(c2);
241 if (index>=t1.size()) break;
246 s1=s1.stripWhiteSpace();
248 // if (!yyextra->PortMapComp.isEmpty())
249 generateMemLink(yyscanner,*yyextra->code,yyextra->PortMapComp,s1);
250 while (index++<t1.size())
253 if (cc==' ' || cc=='\t')
258 yyextra->code->codify(c2);
261 codifyLines(yyscanner,"=>");
266 while (cc==' ' || cc=='\t')
271 yyextra->code->codify(c2);
273 if (index>=t1.size()) break;
276 s2=s2.stripWhiteSpace();
277 if (!checkVhdlString(yyscanner,s2))
279 generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,s2);
281 while (index++<t1.size())
283 if (t1.at(index)==' ')
285 yyextra->code->codify(" ");
291 codifyLines(yyscanner,yytext,yyextra->currClass);
297 codifyLines(yyscanner,yytext);
302 yyextra->braceCount--;
303 writeFont(yyscanner,"vhdlchar",yytext);
304 if (yyextra->braceCount==0)
310 <ParseFuncProto>{NAME} {
311 QCString tmp(yytext);
312 tmp=tmp.stripWhiteSpace();
313 appStringLower(yyextra->prevString,yytext);
314 yyextra->vhdlKeyDict.insert(yyextra->prevString.str());
315 if (!writeColoredWord(yyscanner,tmp))
317 generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,tmp);
322 <ParseType>{STRING} {
323 QCString qcs(yytext);
324 VhdlDocGen::deleteAllChars(qcs,'"');
325 VhdlDocGen::deleteAllChars(qcs,' ');
326 if (VhdlDocGen::isNumber(qcs.str()))
328 writeFont(yyscanner,"vhdllogic",yytext);
332 writeFont(yyscanner,"keyword",yytext);
337 yyextra->funcProto.append(yytext);
338 if (yyextra->isProto)
340 codifyLines(yyscanner,yytext);
347 yyextra->funcProto.append(yytext);
348 if (yyextra->isProto)
350 writeFont(yyscanner,"keyword",yytext);
355 <ParseType>{ENDEFUNC} {
357 codifyLines(yyscanner,yytext,yyextra->currClass);
359 VhdlDocGen::deleteAllChars(tt,';');
360 tt.stripWhiteSpace();
361 static const reg::Ex regg(R"(\s+)"); // any number of whitespace
362 auto ql = split(tt.str(),regg);
363 int index=findIndex(ql,"if")+1;
364 index+=findIndex(ql,"case")+1;
365 index+=findIndex(ql,"loop")+1;
366 index+=findIndex(ql,"generate")+1;
378 codifyLines(yyscanner,yytext,yyextra->currClass);
379 yyextra->vhdlKeyDict.clear();
382 <ParseType>^{B}*("begin "|"begin") {
383 codifyLines(yyscanner,yytext,yyextra->currClass);
384 yyextra->isFuncProto=false;
387 <ParseType>{SPECSIGN} {
388 yyextra->funcProto.append(yytext);
389 if (yyextra->isProto)
391 codifyLines(yyscanner,yytext,yyextra->currClass);
395 <ParseType>["_a-zA-Z0-9]* {
396 QCString val(yytext);
397 yyextra->funcProto.append(yytext);
398 appStringLower(yyextra->prevString,yytext);
400 if (yyextra->isFuncProto && yyextra->braceCount==0)
402 yyextra->vhdlKeyDict.insert(yyextra->prevString.str());
405 if (yyextra->isProto)
407 if (!writeColoredWord(yyscanner,val))
409 if (!yyextra->isFuncProto &&
410 yyextra->vhdlKeyDict.find(yyextra->prevString.str())==yyextra->vhdlKeyDict.end())
412 val=val.stripWhiteSpace();
413 if (VhdlDocGen::isNumber(val.str()))
415 startFontClass(yyscanner,"vhdllogic");
416 codifyLines(yyscanner,yytext,yyextra->currClass);
417 endFontClass(yyscanner);
421 generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,val);
426 codifyLines(yyscanner,yytext,yyextra->currClass);
433 <ParseType>{BRACEOPEN} {
434 yyextra->braceCount++;
435 yyextra->funcProto+='(';
436 if (yyextra->isProto)
438 writeFont(yyscanner,"vhdlchar",yytext);
443 <ParseType>{BRACECLOSE} {
444 yyextra->braceCount--;
445 yyextra->funcProto+=')';
446 if (yyextra->isProto)
448 writeFont(yyscanner,"vhdlchar",yytext);
450 if (yyextra->braceCount==0 && !yyextra->isProto)// && !yyextra->isPackageBody)
452 yyextra->isProto=true;
453 appStringLower(yyextra->prevString,yytext);
454 writeFuncProto(yyscanner);
457 if (yyextra->isPackageBody)
464 <ClassesName>{FUNCNAME} {
465 appStringLower(yyextra->prevString,yytext);
466 yyextra->currClass.resize(0);
467 yyextra->currClass.append(yytext);
468 yyextra->currClass=yyextra->currClass.stripWhiteSpace();
470 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
475 <ParseComponent>{BRACEOPEN} {
476 yyextra->braceCount++;
477 yyextra->code->codify(yytext);
481 <ParseComponent>{BRACECLOSE} {
482 yyextra->braceCount--;
483 yyextra->code->codify(yytext);
484 if (yyextra->braceCount==0 && !yyextra->isComponent)
486 yyextra->tempComp.resize(0);
491 BEGIN(ParseComponent);
495 <ParseComponent>{B}*"-" {
496 if (strlen(yytext)>=2) // found text ?
498 writeFont(yyscanner,"keyword",yytext);
502 writeFont(yyscanner,"vhdlchar",yytext);
506 <ParseComponent>{SPECSIGN} {
507 codifyLines(yyscanner,yytext);
512 <ParseComponent>"\n"|" " {
513 codifyLines(yyscanner,yytext);
516 <ParseComponent>{DIGITSS} {
517 startFontClass(yyscanner,"vhdllogic");
518 codifyLines(yyscanner,yytext);
519 endFontClass(yyscanner);
522 <ParseComponent>{PORT} {
523 codifyLines(yyscanner,yytext);
524 yyextra->braceCount=1;
525 yyextra->isComponent=false;
528 <ParseComponent>{GENERIC} {
529 codifyLines(yyscanner,yytext);
530 yyextra->braceCount=1;
533 <ParseComponent>[_a-zA_Z][_a-zA-Z0-9]* {
534 QCString temp(yytext);
535 appStringLower(yyextra->prevString,yytext);
536 if (!checkVhdlString(yyscanner,temp))
538 if (!writeColoredWord(yyscanner,yyextra->prevString))
540 generateMemLink(yyscanner,*yyextra->code,yyextra->tempComp,temp);
545 <ParseComponent>{STRING} {
546 QCString temp(yytext);
547 if (!checkVhdlString(yyscanner,temp))
549 codifyLines(yyscanner,yytext);
554 <ParseProcessProto>[^()]* {
555 yyextra->funcProto.append(yytext);
560 <ParseProcessProto>{BRACEOPEN} {
561 yyextra->funcProto.append(yytext);
562 yyextra->braceCount++;
565 <ParseProcessProto>{BRACECLOSE} {
566 yyextra->funcProto.append(yytext);
567 yyextra->braceCount--;
568 if (yyextra->braceCount==0)
570 writeProcessProto(yyscanner);
575 <ParsePackage>[^:;]* { //found package
576 StringVector strl=split(yytext,".");
579 std::string s1=strl[0];
580 std::string s2=strl[1];
581 std::string s3=strl[2];
584 codifyLines(yyscanner,s1.c_str(),yyextra->currClass);
585 ClassDef *cd=VhdlDocGen::getPackageName(s2.c_str());
588 generateClassOrGlobalLink(yyscanner,*yyextra->code,s2.c_str());
592 codifyLines(yyscanner,s2.c_str());
594 codifyLines(yyscanner,s3.c_str());
598 writeFont(yyscanner,"keywordflow",yytext);
603 <Bases>{MAPCOMPONENT1}|{MAPCOMPONENT2}|{MAPCOMPONENT3}|{MAPCOMPONENT4} { // found port or generic map
609 QCString left=tt.left(j+1);
610 codifyLines(yyscanner,left);
611 tt=tt.right(tt.length()-j-1);
612 left=VhdlDocGen::getIndexWord(tt,0);
615 j=left.find('(',false);
618 QCString name=left.left(j);
619 generateClassOrGlobalLink(yyscanner,*yyextra->code,name);
620 yyextra->PortMapComp=name;
621 name=tt.right(tt.length()-name.length());
622 codifyLines(yyscanner,name);
626 generateClassOrGlobalLink(yyscanner,*yyextra->code,left);
627 tt.stripPrefix(left); //=tt.right(tt.length()-left.length()-1);
629 yyextra->PortMapComp=left;
630 codifyLines(yyscanner,tt);
636 if (tt.contains(':',false))
638 codifyMapLines(yyscanner,tt);
642 codifyLines(yyscanner,tt);
645 yyextra->braceCount=1;
649 <Bases>^{B}*("component"){BN}+{FUNCNAME} { // found component
650 appStringLower(yyextra->prevString,yytext);
651 QCString temp=VhdlDocGen::getIndexWord(yytext,1);
652 temp=temp.stripWhiteSpace();
653 VhdlDocGen::deleteAllChars(temp,'\n');
654 yyextra->tempComp=temp;
655 codifyLines(yyscanner,yytext,temp,true);
656 yyextra->braceCount=0;
657 yyextra->isComponent=true;
658 BEGIN(ParseComponent);
663 <Bases>{ARCHITECTURE} { // found architecture
664 yyextra->PortMapComp.resize(0);
665 QCString temp = VhdlDocGen::getIndexWord(yytext,3);
666 yyextra->currArch = true;
668 temp+=VhdlDocGen::getIndexWord(yytext,1);
669 yyextra->currClass=temp;
670 VhdlDocGen::deleteAllChars(temp,'\n');
671 codifyLines(yyscanner,yytext,temp,true);
672 yyextra->isPackageBody=false;
676 <Bases>^{B}*("package "){BN}*("body"){BN}*{FUNCNAME} { // found package body
678 QCString temp=VhdlDocGen::getIndexWord(yytext,2);
679 StringVector ql=split(yytext,temp.str());
680 std::string ll=ql[0];
681 codifyLines(yyscanner,ll.c_str(),yyextra->currClass);
682 temp=temp.stripWhiteSpace();
684 generateClassOrGlobalLink(yyscanner,*yyextra->code,temp);
685 yyextra->currClass.resize(0);
686 yyextra->currClass=temp;
687 yyextra->isProto=false;
688 yyextra->isPackageBody=true;
691 <Bases>{PROCESS} { // found process
692 yyextra->isFuncProto=true;
693 yyextra->funcProto.resize(0);
694 yyextra->funcProto.append(yytext);
695 yyextra->vhdlKeyDict.clear();
696 appStringLower(yyextra->prevString,yytext);
697 if (yyextra->prevString.contains('('))
699 yyextra->braceCount=1;
700 BEGIN(ParseProcessProto);
704 writeProcessProto(yyscanner);
708 <Bases>("end"){BN}+("process") { // end of process
709 yyextra->isFuncProto=false;
710 codifyLines(yyscanner,yytext);
715 <Bases>^{B}*("begin "|"begin") {
716 yyextra->isFuncProto=false;
717 writeFont(yyscanner,"vhdlkeyword",yytext);
720 <Bases>^{B}*("use"|"library"){BN}+ { //found package or library
721 writeFont(yyscanner,"vhdlkeyword",yytext);
726 <Bases>^{B}*("use"){BN}+("configuration")[^\n]* {
727 codifyLines(yyscanner,yytext);
730 <Bases>{FUNC} { // found function|procedure
731 yyextra->vhdlKeyDict.clear();
732 yyextra->funcProto.resize(0);
733 yyextra->isProto=false;
734 yyextra->funcProto.append(yytext);
735 yyextra->braceCount=1;
739 <Bases>^{B}*("entity"|"package"){BN}+ {
740 appStringLower(yyextra->prevString,yytext);
741 writeFont(yyscanner,"keywordflow",yytext);
742 yyextra->isPackageBody=false;
746 <Bases>"end"{BN}+"architecture"{BN}+{FUNCNAME} {
747 codifyLines(yyscanner,yytext,yyextra->currClass,true);
748 yyextra->currArch = false;
750 <Bases>"end"{BN}+{FUNCNAME} {
751 if (yyextra->currArch)
753 codifyLines(yyscanner,yytext,yyextra->currClass,true);
754 yyextra->currArch = false;
762 appStringLower(yyextra->prevString,yytext);
763 QCString temp(yytext);
764 temp=temp.stripWhiteSpace();
766 writeColoredWord(yyscanner,temp);
770 appStringLower(yyextra->prevString,yytext);
771 QCString temp(yytext);
772 temp=temp.stripWhiteSpace();
774 if (!writeColoredWord(yyscanner,temp))
776 generateClassOrGlobalLink(yyscanner,*yyextra->code,temp);
780 codifyLines(yyscanner,yytext);
783 <Bases>{KEYWORD} { // found keyword
784 QCString qcs(yytext);
785 if (!writeColoredWord(yyscanner,qcs))
787 startFontClass(yyscanner,"vhdlchar");
788 yyextra->code->codify(yytext);
789 endFontClass(yyscanner);
795 appStringLower(yyextra->prevString,yytext);
796 QCString temp(yytext);
797 temp=temp.stripWhiteSpace();
799 if (!writeColoredWord(yyscanner,temp))
801 startFontClass(yyscanner,"vhdlchar");
802 generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,temp);
803 endFontClass(yyscanner);
807 <Bases,ParseComponent>{DIGITSS} {
808 startFontClass(yyscanner,"vhdllogic");
809 codifyLines(yyscanner,yytext);
810 endFontClass(yyscanner);
813 <Bases>^{B}*("use"){BN}+("entity"|"component")[^\n]* {
814 codifyLines(yyscanner,yytext,yyextra->currClass,true);
819 codifyLines(yyscanner,yytext);
820 if (yyextra->isFuncProto)
822 BEGIN(ParseFuncProto);
831 startFontClass(yyscanner,"vhdlchar");
832 yyextra->code->codify(yytext);
833 endFontClass(yyscanner);
836 <Bases>","|"."|":"|"'"|"("|")" {
837 startFontClass(yyscanner,"vhdlchar");
838 yyextra->code->codify(yytext);
839 endFontClass(yyscanner);
843 QCString qcs(yytext);
844 VhdlDocGen::deleteAllChars(qcs,'"');
845 VhdlDocGen::deleteAllChars(qcs,' ');
847 if (VhdlDocGen::isNumber(qcs.str()))
849 writeFont(yyscanner,"vhdllogic",yytext);
853 writeFont(yyscanner,"keyword",yytext);
857 <Bases>{B}*"#"[^\n]* {
858 writeFont(yyscanner,"keyword",yytext);
861 <Bases>^{B}*{XILINX}/[^a-zA-Z0-9_] {
862 writeWord(yyscanner,yytext);
863 //codifyLines(yyscanner,yytext,yyextra->currClass,true);
866 <Bases>^{B}*"set_"[^\n]* {
867 writeWord(yyscanner,yytext);
871 codifyLines(yyscanner,yytext);
875 <*>[\x80-\xFF]* { // keep utf8 characters together...
876 yyextra->code->codify(yytext);
879 yyextra->code->codify(yytext);
882 <*>\n{TEXTT} { // found normal or special comment on its own line
883 QCString text(yytext);
884 int i=text.find("--");
885 if (text.mid(i,3)=="--!") // && // hide special comment
887 if (!Config_getBool(STRIP_CODE_COMMENTS))
889 codifyLines(yyscanner,text,0,false,true);
891 else yyextra->yyLineNr++; // skip complete line, but count line
893 else // normal comment
895 codifyLines(yyscanner,text,0,false,true);
898 <*>{TEXTT} { // found normal or special comment after something
899 QCString text(yytext);
900 int i=text.find("--");
901 if (text.mid(i,3)=="--!")
903 // hide special comment
904 if (!Config_getBool(STRIP_CODE_COMMENTS))
906 codifyLines(yyscanner,text,0,false,true);
909 else // normal comment
911 codifyLines(yyscanner,text,0,false,true);
917 /*@ ----------------------------------------------------------------------------
920 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
922 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
923 yy_size_t inputPosition = yyextra->inputPosition;
924 const char *s = yyextra->inputString + inputPosition;
926 while( c < max_size && *s)
931 yyextra->inputPosition += c;
935 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
937 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
938 if (Doxygen::searchIndex)
940 if (yyextra->searchCtx)
942 yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),false);
946 yyextra->code->setCurrentDoc(yyextra->sourceFileDef,anchor,true);
951 static bool checkVhdlString(yyscan_t yyscanner,QCString &name)
953 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
954 if (name.isEmpty()) return false;
956 int len=name.length();
957 if (name.at(0)=='"' && name.at(len-1)=='"' && len > 2)
959 std::string inside = name.str().substr(1,len-2);
960 static const reg::Ex regg(R"(\s+)"); // any number of whitespace
961 auto qrl=split(inside,regg);
962 if (VhdlDocGen::isNumber(qrl[0]))
964 yyextra->code->codify("\"");
965 startFontClass(yyscanner,"vhdllogic");
966 yyextra->code->codify(inside.c_str());
967 endFontClass(yyscanner);
968 yyextra->code->codify("\"");
972 startFontClass(yyscanner,"keyword");
973 yyextra->code->codify(name);
974 endFontClass(yyscanner);
979 if (VhdlDocGen::isNumber(name.str()))
981 startFontClass(yyscanner,"vhdllogic");
982 yyextra->code->codify(name);
983 endFontClass(yyscanner);
989 static void addToSearchIndex(yyscan_t yyscanner,const QCString &text)
991 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
992 if (Doxygen::searchIndex)
994 yyextra->code->addWord(text,false);
999 /*! start a new line of code, inserting a line number if yyextra->sourceFileDef
1000 * is true. If a definition starts at the current line, then the line
1001 * number is linked to the documentation of that definition.
1003 static void startCodeLine(yyscan_t yyscanner)
1005 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1006 //if (yyextra->currentFontClass) { yyextra->code->endFontClass(); }
1007 if (yyextra->sourceFileDef)
1009 //QCString lineNumber,lineAnchor;
1010 //lineNumber.sprintf("%05d",yyextra->yyLineNr);
1011 //lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
1012 // if ((yyextra->yyLineNr % 500) == 0)
1013 // fprintf(stderr,"\n starting Line %d:",yyextra->yyLineNr);
1014 const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
1015 //printf("startCodeLine %d d=%s\n", yyextra->yyLineNr,qPrint(d ? d->name()) : "<null>");
1016 if (!yyextra->includeCodeFragment && d)
1018 yyextra->currentDefinition = d;
1019 yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
1020 if (!yyextra->tempComp.isEmpty() && yyextra->currentMemberDef )
1022 //ClassDef *cf=VhdlDocGen::getClass(yyextra->tempComp);
1023 QCString nn=yyextra->currentMemberDef->name();
1024 const MemberDef* mdeff=VhdlDocGen::findMember(yyextra->tempComp,nn);
1027 yyextra->currentMemberDef=mdeff;
1031 QCString lineAnchor;
1032 lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
1033 if (yyextra->currentMemberDef)
1035 yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
1036 yyextra->currentMemberDef->getOutputFileBase(),
1037 yyextra->currentMemberDef->anchor(),yyextra->yyLineNr,
1038 !yyextra->includeCodeFragment);
1039 setCurrentDoc(yyscanner,lineAnchor);
1041 else if (d->isLinkableInProject())
1043 yyextra->code->writeLineNumber(d->getReference(),
1044 d->getOutputFileBase(),
1045 QCString(),yyextra->yyLineNr,
1046 !yyextra->includeCodeFragment);
1047 setCurrentDoc(yyscanner,lineAnchor);
1052 yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
1053 !yyextra->includeCodeFragment);
1056 yyextra->code->startCodeLine(yyextra->sourceFileDef);
1057 yyextra->startCode=true;
1058 if (yyextra->currentFontClass)
1060 yyextra->code->startFontClass(yyextra->currentFontClass);
1064 static void endCodeLine(yyscan_t yyscanner)
1066 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1067 endFontClass(yyscanner);
1068 yyextra->code->endCodeLine();
1071 static void nextCodeLine(yyscan_t yyscanner)
1073 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1074 if (yyextra->startCode)
1076 endCodeLine(yyscanner); // </div>
1078 const char *fc = yyextra->currentFontClass;
1079 if (yyextra->yyLineNr<yyextra->inputLines)
1081 yyextra->currentFontClass = fc;
1082 startCodeLine(yyscanner); //<div>
1086 /*! writes a word to the output.
1087 * If curr_class is defined, the word belongs to a class
1088 * and will be linked.
1091 static void writeWord(yyscan_t yyscanner,const QCString &word,const QCString &curr_class,bool classLink)
1093 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1096 QCString tclass(curr_class);
1098 if (ttt.isEmpty()) return;
1099 for (unsigned int j=0;j<ttt.length();j++)
1102 if (c==' '|| c==',' || c==';' || c==':' || c=='(' || c==')' || c=='\r' || c=='\t' || c=='.')
1106 if (!writeColoredWord(yyscanner,temp)) // is it a keyword ?
1108 //if (VhdlDocGen::findKeyWord(temp))
1109 // writeFont(yyscanner,"vhdlkeyword",temp);
1110 //printf("writeWord: %s\n",qPrint(temp));
1111 if (!tclass.isEmpty())
1115 generateMemLink(yyscanner,*yyextra->code,tclass,temp);
1119 generateClassOrGlobalLink(yyscanner,*yyextra->code,temp,false,curr_class);
1124 if (!checkVhdlString(yyscanner,temp))
1126 yyextra->code->codify(temp);
1137 yyextra->code->codify(cc);
1146 if (!temp.isEmpty())
1148 if (!writeColoredWord(yyscanner,temp))
1150 if (!tclass.isEmpty())
1154 generateMemLink(yyscanner,*yyextra->code,tclass,temp); // generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,left);
1158 generateClassOrGlobalLink(yyscanner,*yyextra->code,temp,false,curr_class);
1164 if (VhdlDocGen::isNumber(qc.str()))
1166 startFontClass(yyscanner,"vhdllogic");
1167 yyextra->code->codify(temp);
1168 endFontClass(yyscanner);
1172 yyextra->code->codify(temp);
1180 /*! write a code fragment 'text' that may span multiple lines, inserting
1181 * line numbers for each line.
1183 static void codifyLines(yyscan_t yyscanner,const QCString &text,const QCString &cl,bool classlink,bool comment)
1185 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1186 if (text.isEmpty()) return;
1187 //printf("codifyLines(%d,\"%s\")\n",yyextra->yyLineNr,text);
1188 const char *p=text.data(),*sp=p;
1194 while ((c=*p++) && c!='\n') {}
1197 yyextra->yyLineNr++;
1199 line = line.left((int)(p-sp)-1);
1202 writeFont(yyscanner,"comment",line);
1206 writeWord(yyscanner,line,cl,classlink);
1208 nextCodeLine(yyscanner);
1214 writeFont(yyscanner,"comment",sp);
1218 writeWord(yyscanner,sp,cl,classlink);
1225 /*! writes a link to a fragment \a text that may span multiple lines, inserting
1226 * line numbers for each line. If \a text contains newlines, the link will be
1227 * split into multiple links with the same destination, one for each line.
1229 static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol,
1230 const Definition *d,
1231 const QCString &text)
1233 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1234 if (text.isEmpty()) return;
1235 static bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
1236 yyextra->tooltipManager.addTooltip(ol,d);
1237 QCString ref = d->getReference();
1238 QCString file = d->getOutputFileBase();
1239 QCString anchor = d->anchor();
1241 if (!sourceTooltips) // fall back to simple "title" tooltips
1243 tooltip = d->briefDescriptionAsTooltip();
1246 const char *p=text.data();
1251 while ((c=*p++) && c!='\n') {}
1254 yyextra->yyLineNr++;
1255 // printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1256 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp,p-sp-1),tooltip);
1257 nextCodeLine(yyscanner);
1261 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,sp,tooltip);
1267 /*! writes a link to a function or procedure
1269 static void generateFuncLink(yyscan_t yyscanner,CodeOutputInterface &ol,const MemberDef* mdef)
1271 //printf("generateFuncLink(FuncName=%s)\n",qPrint(mdef->name()));
1272 QCString memberName=mdef->name();
1274 if (mdef->isLinkable()) // is it a linkable class
1276 writeMultiLineCodeLink(yyscanner,ol,mdef,mdef->name());
1277 addToSearchIndex(yyscanner,memberName);
1280 codifyLines(yyscanner,memberName);
1281 addToSearchIndex(yyscanner,memberName);
1282 } // generateFuncLink
1285 static void generateMemLink(yyscan_t yyscanner,CodeOutputInterface &ol,QCString &clName,QCString& memberName)
1287 if (memberName.isEmpty()) return;
1288 if (clName.isEmpty())
1290 codifyLines(yyscanner,memberName);
1295 QCString className=clName;
1297 //MemberDef *comp=0;
1298 //bool isLocal=false;
1300 const MemberDef *md=VhdlDocGen::findMember(className,memberName);
1301 ClassDef *po=VhdlDocGen::getClass(className);
1303 if (md==0 && po && (VhdlDocGen::VhdlClasses)po->protection()==VhdlDocGen::PACKBODYCLASS)
1305 QCString temp=className;//.stripPrefix("_");
1306 temp.stripPrefix("_");
1307 md=VhdlDocGen::findMember(temp,memberName);
1310 if (md && md->isLinkable()) // is it a linkable class
1312 writeMultiLineCodeLink(yyscanner,ol,md,memberName);
1313 addToSearchIndex(yyscanner,memberName);
1316 // nothing found, just write out the word
1317 codifyLines(yyscanner,memberName);
1318 addToSearchIndex(yyscanner,memberName);
1322 static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol,
1323 const QCString &clName, bool /*typeOnly*/, const QCString &curr_class)
1325 QCString className=clName;
1327 if (className.isEmpty()) return;
1331 //bool isLocal=false;
1332 className.stripPrefix("_");
1333 cd = getClass(className);
1334 if (!cd && !curr_class.isEmpty())
1336 QCString cls = curr_class;
1337 QCString suffix = "::";
1339 if (cls.right(suffix.length())==suffix)
1341 cd = getClass(curr_class);
1347 //className.stripPrefix("_");
1348 QCString temp(clName);
1349 temp.stripPrefix("_");
1350 if (cd && cd->isLinkable()) // is it a linkable class
1352 //if ((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ARCHITECTURECLASS)
1354 // temp=VhdlDocGen::getClassName(cd);
1356 writeMultiLineCodeLink(yyscanner,ol,cd,temp);
1357 addToSearchIndex(yyscanner,className);
1360 Definition *d = cd->getOuterScope();
1361 if (d && d->definitionType()==Definition::TypeClass)
1371 // nothing found, just write out the word
1372 codifyLines(yyscanner,clName);
1373 addToSearchIndex(yyscanner,clName);
1374 }// generateClasss or global link
1377 /*! counts the number of lines in the input */
1378 static int countLines(yyscan_t yyscanner)
1380 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1381 const char *p=yyextra->inputString;
1387 if (c=='\n') count++;
1389 if (p>yyextra->inputString && *(p-1)!='\n')
1390 { // last line does not end with a \n, so we add an extra
1391 // line and explicitly terminate the line after parsing.
1393 yyextra->needsTermination=true;
1398 static void endFontClass(yyscan_t yyscanner)
1400 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1401 if (yyextra->currentFontClass)
1403 yyextra->code->endFontClass();
1404 yyextra->currentFontClass=0;
1408 static void startFontClass(yyscan_t yyscanner,const char *s)
1410 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1412 endFontClass(yyscanner);
1413 yyextra->code->startFontClass(s);
1414 yyextra->currentFontClass=s;
1417 static void writeFont(yyscan_t yyscanner,const char *s,const QCString &text)
1419 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1420 if (s==0 || text.isEmpty()) return;
1421 //printf("writeFont(yyscanner,%d,\"%s\")\n",yyextra->yyLineNr,text);
1422 yyextra->code->startFontClass(s);
1423 yyextra->code->codify(text);
1424 yyextra->code->endFontClass();
1427 //----------------------------------------------------------------------------
1429 static void appStringLower(QCString& qcs,const char* text)
1433 qcs=qcs.stripWhiteSpace();
1436 /* writes and links a port map statement */
1437 static void codifyMapLines(yyscan_t yyscanner,const QCString &text)
1439 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1440 if (text.isEmpty()) return;
1445 //printf("codifyMapLines(%d,\"%s\")\n",yyextra->yyLineNr,qPrint(text));
1446 const char *p=text.data();
1452 while ((c=*p++) && c!='\n' && c!=':' && c != ' ' && c != '(' && c!='\0' && c!='\t')
1457 if (c=='\0') return;
1458 if (!temp.isEmpty()) wordCounter++;
1460 if (!temp.isEmpty())
1462 // different kinds of component instantiations
1463 // xxx:yyy (generic/port) map(
1464 // xxx:(entity/component/configuration) yyy (generic/port) map(
1465 // xxx: entity yyy(zzz) (generic/port) map(
1466 if (wordCounter==2 || wordCounter==3)
1468 QCString q=temp.lower(); // consider (upper/lower) cases
1469 if (q=="entity" || q=="component" || q=="configuration" || q=="port" || q=="generic")
1471 generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,temp);
1475 yyextra->PortMapComp=temp;
1476 generateClassOrGlobalLink(yyscanner,*yyextra->code,temp);
1481 generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,temp);
1485 codifyLines(yyscanner,ctemp);
1492 * writes a function|procedure prototype and links the function|procedure name
1495 static void writeFuncProto(yyscan_t yyscanner)
1497 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1499 VhdlDocGen::parseFuncProto(yyextra->funcProto,name,ret,false);
1503 codifyLines(yyscanner,yyextra->funcProto,yyextra->currClass);
1506 StringVector qlist=split(yyextra->funcProto.str(),name.str());
1507 QCString temp(qlist[0]);
1508 codifyLines(yyscanner,temp,yyextra->currClass);
1509 yyextra->funcProto.stripPrefix(temp);
1511 temp=yyextra->currClass;
1512 if (yyextra->isPackageBody)
1514 temp.stripPrefix("_");// _{package body name}
1516 const MemberDef *mdef=VhdlDocGen::findFunction(name,temp);
1520 generateFuncLink(yyscanner,*yyextra->code,mdef);
1521 yyextra->funcProto.stripPrefix(name);
1522 codifyLines(yyscanner,yyextra->funcProto,yyextra->currClass);
1526 codifyLines(yyscanner,yyextra->funcProto,yyextra->currClass);
1530 /* writes a process prototype to the output */
1532 static void writeProcessProto(yyscan_t yyscanner)
1534 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1535 codifyLines(yyscanner,yyextra->funcProto,yyextra->currClass);
1536 yyextra->vhdlKeyDict.clear();
1537 }// writeProcessProto
1539 /* writes a keyword */
1541 static bool writeColoredWord(yyscan_t yyscanner,QCString& word )
1543 QCString qcs=word.lower();
1544 const char *ss=VhdlDocGen::findKeyWord(qcs);
1547 writeFont(yyscanner,ss,word);
1553 //-----------------------------------------------------------------------------------
1555 struct VHDLCodeParser::Private
1558 vhdlcodeYY_state state;
1561 VHDLCodeParser::VHDLCodeParser() : p(std::make_unique<Private>())
1563 vhdlcodeYYlex_init_extra(&p->state,&p->yyscanner);
1565 vhdlcodeYYset_debug(1,p->yyscanner);
1567 resetCodeParserState();
1570 VHDLCodeParser::~VHDLCodeParser()
1572 vhdlcodeYYlex_destroy(p->yyscanner);
1575 void VHDLCodeParser::resetCodeParserState()
1577 p->state.vhdlKeyDict.clear();
1580 void VHDLCodeParser::parseCode(CodeOutputInterface &od,
1581 const QCString &className,
1585 const QCString &exName,
1589 bool inlineFragment,
1590 const MemberDef *memberDef,
1592 const Definition *searchCtx,
1593 bool /* collectXRefs */)
1595 yyscan_t yyscanner = p->yyscanner;
1596 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1597 //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd);
1598 if (s.isEmpty()) return;
1599 printlex(yy_flex_debug, true, __FILE__, fd ? qPrint(fd->fileName()): NULL);
1602 const ClassDef *dd=memberDef->getClassDef();
1603 if (dd) yyextra->currClass=dd->name();
1605 resetCodeParserState();
1606 yyextra->code = &od;
1607 yyextra->inputString = s.data();
1608 yyextra->inputPosition = 0;
1609 yyextra->currentFontClass = 0;
1610 yyextra->needsTermination = false;
1611 yyextra->searchCtx = searchCtx;
1614 yyextra->yyLineNr = startLine;
1616 yyextra->yyLineNr = 1;
1619 yyextra->inputLines = endLine+1;
1621 yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
1624 // yyextra->theCallContext.clear();
1625 yyextra->exampleBlock = exBlock;
1626 yyextra->exampleName = exName;
1627 yyextra->sourceFileDef = fd;
1628 bool cleanupSourceDef = false;
1629 if (exBlock && fd==0)
1631 // create a dummy filedef for the example
1632 yyextra->sourceFileDef = createFileDef("",exName);
1633 cleanupSourceDef = true;
1635 if (yyextra->sourceFileDef)
1637 setCurrentDoc(yyscanner,"l00001");
1639 yyextra->currentDefinition = 0;
1640 yyextra->currentMemberDef = 0;
1641 yyextra->vhdlMember=0;
1642 if (!yyextra->exampleName.isEmpty())
1644 yyextra->exampleFile = convertNameToFile(yyextra->exampleName+"-example");
1646 yyextra->includeCodeFragment = inlineFragment;
1647 startCodeLine(yyscanner);
1648 if (!yyextra->lexInit)
1651 yyextra->lexInit=true;
1653 /*int iLine=*/countLines(yyscanner);
1654 vhdlcodeYYrestart( 0, yyscanner );
1656 vhdlcodeYYlex(yyscanner);
1657 if (yyextra->needsTermination)
1659 endCodeLine(yyscanner);
1661 if (cleanupSourceDef)
1663 // delete the temporary file definition used for this example
1664 delete yyextra->sourceFileDef;
1665 yyextra->sourceFileDef=0;
1667 yyextra->startCode=false;
1669 // write the tooltips
1670 yyextra->tooltipManager.writeTooltips(od);
1672 printlex(yy_flex_debug, false, __FILE__, fd ? qPrint(fd->fileName()): NULL);
1675 #if USE_STATE2STRING
1676 #include "vhdlcode.l.h"