/****************************************************************************** * * Copyright (C) 1997-2020 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * * Documents produced by Doxygen are derivative works derived from the * input used in their production; they are not affected by this license. * */ /****************************************************************************** * Parser for syntax highlighting and references for vhdl subset * written by M. Kreis * supports VHDL-87/93/2008 ******************************************************************************/ %option never-interactive %option case-insensitive %option prefix="vhdlcodeYY" %option reentrant %option extra-type="struct vhdlcodeYY_state *" %top{ #include } %{ #include #include /* * includes */ #include #include #include #include "vhdlcode.h" #include "entry.h" #include "doxygen.h" #include "message.h" #include "outputlist.h" #include "util.h" #include "membername.h" #include "searchindex.h" #include "vhdldocgen.h" #include "arguments.h" #include "config.h" #include "classdef.h" #include "filedef.h" #include "tooltip.h" #include "regex.h" #define YY_NO_INPUT 1 #define YY_NO_UNISTD_H 1 #define USE_STATE2STRING 0 // Toggle for some debugging info //#define DBG_CTX(x) fprintf x #define DBG_CTX(x) do { } while(0) /* ----------------------------------------------------------------- * statics */ // ----------------- ---------------------------------- struct vhdlcodeYY_state { bool isFuncProto = false; bool isComponent = false; bool isPackageBody = false; bool isProto = false; bool startCode = false; QCString prevString; QCString currClass; std::unordered_set vhdlKeyDict; QCString tempComp; QCString PortMapComp; const MemberDef * vhdlMember = 0; QCString funcProto; CodeOutputInterface * code = 0; const char * inputString = 0; //!< the code fragment as text yy_size_t inputPosition = 0; //!< read offset during parsing int inputLines = 0; //!< number of line in the code fragment int yyLineNr = 0; //!< current line number bool needsTermination = false; const Definition *searchCtx = 0; bool exampleBlock = false; QCString exampleName; QCString exampleFile; bool currArch = false; const FileDef * sourceFileDef = 0; const Definition * currentDefinition = 0; const MemberDef * currentMemberDef = 0; bool includeCodeFragment = false; const char * currentFontClass = 0; bool lexInit = false; int braceCount = 0; }; static void writeFont(yyscan_t yyscanner,const char *s,const QCString &text); static void generateMemLink(yyscan_t yyscanner,CodeOutputInterface &ol,QCString &clName,QCString& memberName); static bool writeColoredWord(yyscan_t yyscanner,QCString& word ); static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol,const QCString &clName, bool typeOnly=false, const QCString &curr_class=QCString()); static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor); static bool checkVhdlString(yyscan_t yyscanner,QCString &name); static void addToSearchIndex(yyscan_t yyscanner,const QCString &text); static void startCodeLine(yyscan_t yyscanner); static void endCodeLine(yyscan_t yyscanner); static void nextCodeLine(yyscan_t yyscanner); static void writeWord(yyscan_t yyscanner,const QCString &word,const QCString &curr_class=QCString(),bool classLink=false); static void codifyLines(yyscan_t yyscanner,const QCString &text,const QCString &cl=QCString(),bool classlink=false,bool comment=false); static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol, const Definition *d, const QCString &text); static void generateFuncLink(yyscan_t yyscanner,CodeOutputInterface &ol,const MemberDef* mdef); static int countLines(yyscan_t yyscanner); static void endFontClass(yyscan_t yyscanner); static void startFontClass(yyscan_t yyscanner,const char *s); static void appStringLower(QCString& qcs,const char* text); static void codifyMapLines(yyscan_t yyscanner,const QCString &text); static void writeFuncProto(yyscan_t yyscanner); static void writeProcessProto(yyscan_t yyscanner); static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size); #if USE_STATE2STRING static const char *stateToString(int state); #endif //------------------------------------------------------------------- #undef YY_INPUT #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size); %} B [ \t] BN [ \t\n\r] STRING ["][^"\n]*["] NAME [a-z_A-Z][ a-z_A-Z0-9]* FUNCNAME [a-z_A-Z"][a-z_A-Z0-9+*"/=<>-]* ID "$"?[a-z_A-Z][a-z_A-Z0-9]* SPECSIGN [:;, +*&\/=<>'\t]* DIGITSS [0-9]+|[0-9]+("#")*[0-9_a-fA-F\+\.\-]+("#")* ALLTYPESMAP {B}*[_a-zA-Z0-9. ]+{BN}* ALLTYPESMAP1 {BN}*[_a-zA-Z0-9.() ]+{BN}* ARCHITECTURE ^{B}*("architecture"){BN}+{FUNCNAME}{BN}+("of"){BN}+{FUNCNAME}{BN}+("is") PROCESS ({BN}*{FUNCNAME}{BN}*[:]+{BN}*("process"){BN}*[(]*)|[^a-zA-Z]("process "|"process("){BN}*[ (]*|[^a-zA-Z]("process"){BN}+ END1 {B}*("end "){BN}+("if"|"case"|"loop"|"generate"|"for") END2 [^a-zA-Z_]("end"){BN}*[;] END3 {BN}*[^a-zA-Z]("end"){BN}+{FUNCNAME}{BN}*[;] END4 {B}*("end"){BN}+"function"{BN}+{FUNCNAME}{BN}*[;] ENDEFUNC {END3}|{END4}|{END2} KEYWORD ("of"|"new"|"event"|"break"|"case"|"end"|"loop"|"else"|"for"|"goto"|"if"|"return"|"generate"|"is"|"while"|"in") TYPEKW ^{B}*("type"|"subtype"|"constant"|"attribute"|"signal"|"variable","alias","configuration") FUNC ^{B}*("function"|"procedure"){BN}*{FUNCNAME}{BN}*("(") ARITHOP "+"|"-"|"/"|"*"|"%"|"/="|":=" ASSIGNOP "="|"*="|"/="|"%="|"+="|"-="|"<<="|">>="|"&="|"^="|"|=" LOGICOP "=="|"!="|">"|"<"|">="|"<="|"&&"|"||"|"!" BITOP "&"|"|"|"^"|"<<"|">>"|"~" OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP} PORT {B}*("port"){BN}*("(") GENERIC {B}*("generic"){BN}*("(") BRACEOPEN [(]{1} BRACECLOSE [)]{1} TEXTT {B}*"--"[^\n]* MAPCOMPONENT1 ({ALLTYPESMAP}[:]{ALLTYPESMAP}{TEXTT}*{BN}+("port"|"generic"){BN}+("map"){BN}*("("){1}) MAPCOMPONENT2 {BN}*("port"|"generic"){BN}+("map"){BN}*("("){1} MAPCOMPONENT3 ({ALLTYPESMAP}[:]{BN}*{ALLTYPESMAP1}{TEXTT}*{BN}+("port"|"generic"){BN}+("map"){BN}*("("){1}) MAPCOMPONENT4 ({ALLTYPESMAP}[:]{BN}*("entity"|"component"|"configuration"){BN}+{ALLTYPESMAP1}{TEXTT}*{BN}*("port"|"generic"){BN}*("map"){BN}*("("){1}) 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" %option noyywrap %option nounput %x Bases %x ParseType %x ParseFuncProto %x ParseComponent %x ParsePackage %x ParseProcessProto %x ClassName %x PackageName %x ClassVar %x ClassesName %x Map %x End %x Body %% . { BEGIN(Bases); } {BRACEOPEN} { yyextra->braceCount++; writeFont(yyscanner,"vhdlchar",yytext); BEGIN(Map); } [^()\n,--]* { /* write and link a port map lines */ QCString tt(yytext); VhdlDocGen::deleteAllChars(tt,','); auto ql = split(tt.str(),"=>"); if (ql.size()>=2) { unsigned int index=0; QCString t1(ql[0]); char cc=t1.at(index); while (cc==' ' || cc=='\t') { char c2[2]; c2[0]=cc; c2[1]=0; yyextra->code->codify(c2); index++; if (index>=t1.size()) break; cc=t1.at(index); } QCString s1=t1; s1=s1.stripWhiteSpace(); // if (!yyextra->PortMapComp.isEmpty()) generateMemLink(yyscanner,*yyextra->code,yyextra->PortMapComp,s1); while (index++code->codify(c2); } } codifyLines(yyscanner,"=>"); index=0; QCString s2(ql[1]); t1=s2; cc=t1.at(index); while (cc==' ' || cc=='\t') { char c2[2]; c2[0]=cc; c2[1]=0; yyextra->code->codify(c2); index++; if (index>=t1.size()) break; cc=t1.at(index); } s2=s2.stripWhiteSpace(); if (!checkVhdlString(yyscanner,s2)) { generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,s2); } while (index++code->codify(" "); } } } else { codifyLines(yyscanner,yytext,yyextra->currClass); } BEGIN(Map); } "\n"|"," { codifyLines(yyscanner,yytext); BEGIN(Map); } {BRACECLOSE} { yyextra->braceCount--; writeFont(yyscanner,"vhdlchar",yytext); if (yyextra->braceCount==0) { BEGIN(Bases); } } {NAME} { QCString tmp(yytext); tmp=tmp.stripWhiteSpace(); appStringLower(yyextra->prevString,yytext); yyextra->vhdlKeyDict.insert(yyextra->prevString.str()); if (!writeColoredWord(yyscanner,tmp)) { generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,tmp); } BEGIN(Bases); } {STRING} { QCString qcs(yytext); VhdlDocGen::deleteAllChars(qcs,'"'); VhdlDocGen::deleteAllChars(qcs,' '); if (VhdlDocGen::isNumber(qcs.str())) { writeFont(yyscanner,"vhdllogic",yytext); } else { writeFont(yyscanner,"keyword",yytext); } } "\n" { yyextra->funcProto.append(yytext); if (yyextra->isProto) { codifyLines(yyscanner,yytext); } BEGIN(ParseType); } {TEXTT} { yyextra->funcProto.append(yytext); if (yyextra->isProto) { writeFont(yyscanner,"keyword",yytext); } BEGIN(ParseType); } {ENDEFUNC} { QCString tt(yytext); codifyLines(yyscanner,yytext,yyextra->currClass); tt=tt.lower(); VhdlDocGen::deleteAllChars(tt,';'); tt.stripWhiteSpace(); static const reg::Ex regg(R"(\s+)"); // any number of whitespace auto ql = split(tt.str(),regg); int index=findIndex(ql,"if")+1; index+=findIndex(ql,"case")+1; index+=findIndex(ql,"loop")+1; index+=findIndex(ql,"generate")+1; if (index==0) { BEGIN(Bases); } else { BEGIN(ParseType); } } {END1} { codifyLines(yyscanner,yytext,yyextra->currClass); yyextra->vhdlKeyDict.clear(); } ^{B}*("begin "|"begin") { codifyLines(yyscanner,yytext,yyextra->currClass); yyextra->isFuncProto=false; } {SPECSIGN} { yyextra->funcProto.append(yytext); if (yyextra->isProto) { codifyLines(yyscanner,yytext,yyextra->currClass); } } ["_a-zA-Z0-9]* { QCString val(yytext); yyextra->funcProto.append(yytext); appStringLower(yyextra->prevString,yytext); if (yyextra->isFuncProto && yyextra->braceCount==0) { yyextra->vhdlKeyDict.insert(yyextra->prevString.str()); } if (yyextra->isProto) { if (!writeColoredWord(yyscanner,val)) { if (!yyextra->isFuncProto && yyextra->vhdlKeyDict.find(yyextra->prevString.str())==yyextra->vhdlKeyDict.end()) { val=val.stripWhiteSpace(); if (VhdlDocGen::isNumber(val.str())) { startFontClass(yyscanner,"vhdllogic"); codifyLines(yyscanner,yytext,yyextra->currClass); endFontClass(yyscanner); } else { generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,val); } } else { codifyLines(yyscanner,yytext,yyextra->currClass); } } } BEGIN(ParseType); } {BRACEOPEN} { yyextra->braceCount++; yyextra->funcProto+='('; if (yyextra->isProto) { writeFont(yyscanner,"vhdlchar",yytext); } BEGIN(ParseType); } {BRACECLOSE} { yyextra->braceCount--; yyextra->funcProto+=')'; if (yyextra->isProto) { writeFont(yyscanner,"vhdlchar",yytext); } if (yyextra->braceCount==0 && !yyextra->isProto)// && !yyextra->isPackageBody) { yyextra->isProto=true; appStringLower(yyextra->prevString,yytext); writeFuncProto(yyscanner); BEGIN(Bases); } if (yyextra->isPackageBody) { BEGIN(ParseType); } } {FUNCNAME} { appStringLower(yyextra->prevString,yytext); yyextra->currClass.resize(0); yyextra->currClass.append(yytext); yyextra->currClass=yyextra->currClass.stripWhiteSpace(); generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext); BEGIN(Bases); } {BRACEOPEN} { yyextra->braceCount++; yyextra->code->codify(yytext); } {BRACECLOSE} { yyextra->braceCount--; yyextra->code->codify(yytext); if (yyextra->braceCount==0 && !yyextra->isComponent) { yyextra->tempComp.resize(0); BEGIN(Bases); } else { BEGIN(ParseComponent); } } {B}*"-" { if (strlen(yytext)>=2) // found text ? { writeFont(yyscanner,"keyword",yytext); } else { writeFont(yyscanner,"vhdlchar",yytext); } } {SPECSIGN} { codifyLines(yyscanner,yytext); } "\n"|" " { codifyLines(yyscanner,yytext); } {DIGITSS} { startFontClass(yyscanner,"vhdllogic"); codifyLines(yyscanner,yytext); endFontClass(yyscanner); } {PORT} { codifyLines(yyscanner,yytext); yyextra->braceCount=1; yyextra->isComponent=false; } {GENERIC} { codifyLines(yyscanner,yytext); yyextra->braceCount=1; } [_a-zA_Z][_a-zA-Z0-9]* { QCString temp(yytext); appStringLower(yyextra->prevString,yytext); if (!checkVhdlString(yyscanner,temp)) { if (!writeColoredWord(yyscanner,yyextra->prevString)) { generateMemLink(yyscanner,*yyextra->code,yyextra->tempComp,temp); } } } {STRING} { QCString temp(yytext); if (!checkVhdlString(yyscanner,temp)) { codifyLines(yyscanner,yytext); } } [^()]* { yyextra->funcProto.append(yytext); } {BRACEOPEN} { yyextra->funcProto.append(yytext); yyextra->braceCount++; } {BRACECLOSE} { yyextra->funcProto.append(yytext); yyextra->braceCount--; if (yyextra->braceCount==0) { writeProcessProto(yyscanner); BEGIN(Bases); } } [^:;]* { //found package StringVector strl=split(yytext,"."); if (strl.size()>2) { std::string s1=strl[0]; std::string s2=strl[1]; std::string s3=strl[2]; s1.append("."); s3.insert(0,"."); codifyLines(yyscanner,s1.c_str(),yyextra->currClass); ClassDef *cd=VhdlDocGen::getPackageName(s2.c_str()); if (cd) { generateClassOrGlobalLink(yyscanner,*yyextra->code,s2.c_str()); } else { codifyLines(yyscanner,s2.c_str()); } codifyLines(yyscanner,s3.c_str()); } else { writeFont(yyscanner,"keywordflow",yytext); } BEGIN(Bases); } {MAPCOMPONENT1}|{MAPCOMPONENT2}|{MAPCOMPONENT3}|{MAPCOMPONENT4} { // found port or generic map QCString tt(yytext); int j=tt.find('.'); if (j>0) { QCString left=tt.left(j+1); codifyLines(yyscanner,left); tt=tt.right(tt.length()-j-1); left=VhdlDocGen::getIndexWord(tt,0); if (!left.isEmpty()) { if (left.contains('(')) { j=left.find('(',false); QCString name=left.left(j); generateClassOrGlobalLink(yyscanner,*yyextra->code,name); yyextra->PortMapComp=name; name=tt.right(tt.length()-name.length()); codifyLines(yyscanner,name); } else { generateClassOrGlobalLink(yyscanner,*yyextra->code,left); tt.stripPrefix(left); //=tt.right(tt.length()-left.length()-1); yyextra->PortMapComp=left; codifyLines(yyscanner,tt); } } } else { if (tt.contains(':',false)) { codifyMapLines(yyscanner,tt); } else { codifyLines(yyscanner,tt); } } yyextra->braceCount=1; BEGIN(Map); } ^{B}*("component"){BN}+{FUNCNAME} { // found component appStringLower(yyextra->prevString,yytext); QCString temp=VhdlDocGen::getIndexWord(yytext,1); temp=temp.stripWhiteSpace(); VhdlDocGen::deleteAllChars(temp,'\n'); yyextra->tempComp=temp; codifyLines(yyscanner,yytext,temp,true); yyextra->braceCount=0; yyextra->isComponent=true; BEGIN(ParseComponent); } {ARCHITECTURE} { // found architecture yyextra->PortMapComp.resize(0); QCString temp = VhdlDocGen::getIndexWord(yytext,3); yyextra->currArch = true; temp+="::"; temp+=VhdlDocGen::getIndexWord(yytext,1); yyextra->currClass=temp; VhdlDocGen::deleteAllChars(temp,'\n'); codifyLines(yyscanner,yytext,temp,true); yyextra->isPackageBody=false; } ^{B}*("package "){BN}*("body"){BN}*{FUNCNAME} { // found package body QCString ss(yytext); QCString temp=VhdlDocGen::getIndexWord(yytext,2); StringVector ql=split(yytext,temp.str()); std::string ll=ql[0]; codifyLines(yyscanner,ll.c_str(),yyextra->currClass); temp=temp.stripWhiteSpace(); temp.prepend("_"); generateClassOrGlobalLink(yyscanner,*yyextra->code,temp); yyextra->currClass.resize(0); yyextra->currClass=temp; yyextra->isProto=false; yyextra->isPackageBody=true; } {PROCESS} { // found process yyextra->isFuncProto=true; yyextra->funcProto.resize(0); yyextra->funcProto.append(yytext); yyextra->vhdlKeyDict.clear(); appStringLower(yyextra->prevString,yytext); if (yyextra->prevString.contains('(')) { yyextra->braceCount=1; BEGIN(ParseProcessProto); } else { writeProcessProto(yyscanner); } } ("end"){BN}+("process") { // end of process yyextra->isFuncProto=false; codifyLines(yyscanner,yytext); BEGIN(Bases); } ^{B}*("begin "|"begin") { yyextra->isFuncProto=false; writeFont(yyscanner,"vhdlkeyword",yytext); } ^{B}*("use"|"library"){BN}+ { //found package or library writeFont(yyscanner,"vhdlkeyword",yytext); BEGIN(ParsePackage); } ^{B}*("use"){BN}+("configuration")[^\n]* { codifyLines(yyscanner,yytext); } {FUNC} { // found function|procedure yyextra->vhdlKeyDict.clear(); yyextra->funcProto.resize(0); yyextra->isProto=false; yyextra->funcProto.append(yytext); yyextra->braceCount=1; BEGIN(ParseType); } ^{B}*("entity"|"package"){BN}+ { appStringLower(yyextra->prevString,yytext); writeFont(yyscanner,"keywordflow",yytext); yyextra->isPackageBody=false; BEGIN(ClassesName); } "end"{BN}+"architecture"{BN}+{FUNCNAME} { codifyLines(yyscanner,yytext,yyextra->currClass,true); yyextra->currArch = false; } "end"{BN}+{FUNCNAME} { if (yyextra->currArch) { codifyLines(yyscanner,yytext,yyextra->currClass,true); yyextra->currArch = false; } else { REJECT; } } "end" { appStringLower(yyextra->prevString,yytext); QCString temp(yytext); temp=temp.stripWhiteSpace(); writeColoredWord(yyscanner,temp); BEGIN(End); } {ID} { appStringLower(yyextra->prevString,yytext); QCString temp(yytext); temp=temp.stripWhiteSpace(); if (!writeColoredWord(yyscanner,temp)) { generateClassOrGlobalLink(yyscanner,*yyextra->code,temp); } } ";" { codifyLines(yyscanner,yytext); BEGIN(Bases); } {KEYWORD} { // found keyword QCString qcs(yytext); if (!writeColoredWord(yyscanner,qcs)) { startFontClass(yyscanner,"vhdlchar"); yyextra->code->codify(yytext); endFontClass(yyscanner); } } {ID} { appStringLower(yyextra->prevString,yytext); QCString temp(yytext); temp=temp.stripWhiteSpace(); if (!writeColoredWord(yyscanner,temp)) { startFontClass(yyscanner,"vhdlchar"); generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,temp); endFontClass(yyscanner); } } {DIGITSS} { startFontClass(yyscanner,"vhdllogic"); codifyLines(yyscanner,yytext); endFontClass(yyscanner); } ^{B}*("use"){BN}+("entity"|"component")[^\n]* { codifyLines(yyscanner,yytext,yyextra->currClass,true); } {TYPEKW} { codifyLines(yyscanner,yytext); if (yyextra->isFuncProto) { BEGIN(ParseFuncProto); } else { BEGIN(Bases); } } {OPERATOR} { startFontClass(yyscanner,"vhdlchar"); yyextra->code->codify(yytext); endFontClass(yyscanner); } ","|"."|":"|"'"|"("|")" { startFontClass(yyscanner,"vhdlchar"); yyextra->code->codify(yytext); endFontClass(yyscanner); } {STRING} { QCString qcs(yytext); VhdlDocGen::deleteAllChars(qcs,'"'); VhdlDocGen::deleteAllChars(qcs,' '); if (VhdlDocGen::isNumber(qcs.str())) { writeFont(yyscanner,"vhdllogic",yytext); } else { writeFont(yyscanner,"keyword",yytext); } } {B}*"#"[^\n]* { writeFont(yyscanner,"keyword",yytext); } ^{B}*{XILINX}/[^a-zA-Z0-9_] { writeWord(yyscanner,yytext); //codifyLines(yyscanner,yytext,yyextra->currClass,true); } ^{B}*"set_"[^\n]* { writeWord(yyscanner,yytext); } <*>\n { codifyLines(yyscanner,yytext); BEGIN(Bases); } <*>[\x80-\xFF]* { // keep utf8 characters together... yyextra->code->codify(yytext); } <*>. { yyextra->code->codify(yytext); } <*>\n{TEXTT} { // found normal or special comment on its own line QCString text(yytext); int i=text.find("--"); if (text.mid(i,3)=="--!") // && // hide special comment { if (!Config_getBool(STRIP_CODE_COMMENTS)) { codifyLines(yyscanner,text,0,false,true); } else yyextra->yyLineNr++; // skip complete line, but count line } else // normal comment { codifyLines(yyscanner,text,0,false,true); } } <*>{TEXTT} { // found normal or special comment after something QCString text(yytext); int i=text.find("--"); if (text.mid(i,3)=="--!") { // hide special comment if (!Config_getBool(STRIP_CODE_COMMENTS)) { codifyLines(yyscanner,text,0,false,true); } } else // normal comment { codifyLines(yyscanner,text,0,false,true); } } %% /*@ ---------------------------------------------------------------------------- */ static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; yy_size_t inputPosition = yyextra->inputPosition; const char *s = yyextra->inputString + inputPosition; yy_size_t c=0; while( c < max_size && *s) { *buf++ = *s++; c++; } yyextra->inputPosition += c; return c; } static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (Doxygen::searchIndex) { if (yyextra->searchCtx) { yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),false); } else { yyextra->code->setCurrentDoc(yyextra->sourceFileDef,anchor,true); } } } static bool checkVhdlString(yyscan_t yyscanner,QCString &name) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (name.isEmpty()) return false; int len=name.length(); if (name.at(0)=='"' && name.at(len-1)=='"' && len > 2) { std::string inside = name.str().substr(1,len-2); static const reg::Ex regg(R"(\s+)"); // any number of whitespace auto qrl=split(inside,regg); if (VhdlDocGen::isNumber(qrl[0])) { yyextra->code->codify("\""); startFontClass(yyscanner,"vhdllogic"); yyextra->code->codify(inside.c_str()); endFontClass(yyscanner); yyextra->code->codify("\""); } else { startFontClass(yyscanner,"keyword"); yyextra->code->codify(name); endFontClass(yyscanner); } return true; } if (VhdlDocGen::isNumber(name.str())) { startFontClass(yyscanner,"vhdllogic"); yyextra->code->codify(name); endFontClass(yyscanner); return true; } return false; } static void addToSearchIndex(yyscan_t yyscanner,const QCString &text) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (Doxygen::searchIndex) { yyextra->code->addWord(text,false); } } /*! start a new line of code, inserting a line number if yyextra->sourceFileDef * is true. If a definition starts at the current line, then the line * number is linked to the documentation of that definition. */ static void startCodeLine(yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; //if (yyextra->currentFontClass) { yyextra->code->endFontClass(); } if (yyextra->sourceFileDef) { //QCString lineNumber,lineAnchor; //lineNumber.sprintf("%05d",yyextra->yyLineNr); //lineAnchor.sprintf("l%05d",yyextra->yyLineNr); // if ((yyextra->yyLineNr % 500) == 0) // fprintf(stderr,"\n starting Line %d:",yyextra->yyLineNr); const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr); //printf("startCodeLine %d d=%s\n", yyextra->yyLineNr,qPrint(d ? d->name()) : ""); if (!yyextra->includeCodeFragment && d) { yyextra->currentDefinition = d; yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr); if (!yyextra->tempComp.isEmpty() && yyextra->currentMemberDef ) { //ClassDef *cf=VhdlDocGen::getClass(yyextra->tempComp); QCString nn=yyextra->currentMemberDef->name(); const MemberDef* mdeff=VhdlDocGen::findMember(yyextra->tempComp,nn); if (mdeff) { yyextra->currentMemberDef=mdeff; } } QCString lineAnchor; lineAnchor.sprintf("l%05d",yyextra->yyLineNr); if (yyextra->currentMemberDef) { yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(), yyextra->currentMemberDef->getOutputFileBase(), yyextra->currentMemberDef->anchor(),yyextra->yyLineNr); setCurrentDoc(yyscanner,lineAnchor); } else if (d->isLinkableInProject()) { yyextra->code->writeLineNumber(d->getReference(), d->getOutputFileBase(), QCString(),yyextra->yyLineNr); setCurrentDoc(yyscanner,lineAnchor); } } else { yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr); } } yyextra->code->startCodeLine(yyextra->sourceFileDef); yyextra->startCode=true; if (yyextra->currentFontClass) { yyextra->code->startFontClass(yyextra->currentFontClass); } } static void endCodeLine(yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; endFontClass(yyscanner); yyextra->code->endCodeLine(); } static void nextCodeLine(yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (yyextra->startCode) { endCodeLine(yyscanner); // } const char *fc = yyextra->currentFontClass; if (yyextra->yyLineNrinputLines) { yyextra->currentFontClass = fc; startCodeLine(yyscanner); //
} } /*! writes a word to the output. * If curr_class is defined, the word belongs to a class * and will be linked. */ static void writeWord(yyscan_t yyscanner,const QCString &word,const QCString &curr_class,bool classLink) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool found=false; QCString temp; QCString tclass(curr_class); QCString ttt(word); if (ttt.isEmpty()) return; for (unsigned int j=0;jcode,tclass,temp); } else { generateClassOrGlobalLink(yyscanner,*yyextra->code,temp,false,curr_class); } } else { if (!checkVhdlString(yyscanner,temp)) { yyextra->code->codify(temp); } } } temp.resize(0); found=false; } char cc[2]; cc[0]=c; cc[1]=0; yyextra->code->codify(cc); } else { found=true; temp+=c; } } // for if (!temp.isEmpty()) { if (!writeColoredWord(yyscanner,temp)) { if (!tclass.isEmpty()) { if (!classLink) { generateMemLink(yyscanner,*yyextra->code,tclass,temp); // generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,left); } else { generateClassOrGlobalLink(yyscanner,*yyextra->code,temp,false,curr_class); } } else { QCString qc(temp); if (VhdlDocGen::isNumber(qc.str())) { startFontClass(yyscanner,"vhdllogic"); yyextra->code->codify(temp); endFontClass(yyscanner); } else { yyextra->code->codify(temp); } } } } }// writeWord /*! write a code fragment 'text' that may span multiple lines, inserting * line numbers for each line. */ static void codifyLines(yyscan_t yyscanner,const QCString &text,const QCString &cl,bool classlink,bool comment) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (text.isEmpty()) return; //printf("codifyLines(%d,\"%s\")\n",yyextra->yyLineNr,text); const char *p=text.data(),*sp=p; char c; bool done=false; while (!done) { sp=p; while ((c=*p++) && c!='\n') {} if (c=='\n') { yyextra->yyLineNr++; QCString line = sp; line = line.left((int)(p-sp)-1); if (comment) { writeFont(yyscanner,"comment",line); } else { writeWord(yyscanner,line,cl,classlink); } nextCodeLine(yyscanner); } else { if (comment) { writeFont(yyscanner,"comment",sp); } else { writeWord(yyscanner,sp,cl,classlink); } done=true; } } } /*! writes a link to a fragment \a text that may span multiple lines, inserting * line numbers for each line. If \a text contains newlines, the link will be * split into multiple links with the same destination, one for each line. */ static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol, const Definition *d, const QCString &text) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (text.isEmpty()) return; static bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS); TooltipManager::instance().addTooltip(ol,d); QCString ref = d->getReference(); QCString file = d->getOutputFileBase(); QCString anchor = d->anchor(); QCString tooltip; if (!sourceTooltips) // fall back to simple "title" tooltips { tooltip = d->briefDescriptionAsTooltip(); } bool done=false; const char *p=text.data(); while (!done) { const char *sp=p; char c; while ((c=*p++) && c!='\n') {} if (c=='\n') { yyextra->yyLineNr++; // printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp); ol.writeCodeLink(ref,file,anchor,QCString(sp,p-sp-1),tooltip); nextCodeLine(yyscanner); } else { ol.writeCodeLink(ref,file,anchor,sp,tooltip); done=true; } } } /*! writes a link to a function or procedure */ static void generateFuncLink(yyscan_t yyscanner,CodeOutputInterface &ol,const MemberDef* mdef) { //printf("generateFuncLink(FuncName=%s)\n",qPrint(mdef->name())); QCString memberName=mdef->name(); if (mdef->isLinkable()) // is it a linkable class { writeMultiLineCodeLink(yyscanner,ol,mdef,mdef->name()); addToSearchIndex(yyscanner,memberName); return; } codifyLines(yyscanner,memberName); addToSearchIndex(yyscanner,memberName); } // generateFuncLink static void generateMemLink(yyscan_t yyscanner,CodeOutputInterface &ol,QCString &clName,QCString& memberName) { if (memberName.isEmpty()) return; if (clName.isEmpty()) { codifyLines(yyscanner,memberName); return; } QCString className=clName; //MemberDef *comp=0; //bool isLocal=false; const MemberDef *md=VhdlDocGen::findMember(className,memberName); ClassDef *po=VhdlDocGen::getClass(className); if (md==0 && po && (VhdlDocGen::VhdlClasses)po->protection()==VhdlDocGen::PACKBODYCLASS) { QCString temp=className;//.stripPrefix("_"); temp.stripPrefix("_"); md=VhdlDocGen::findMember(temp,memberName); } if (md && md->isLinkable()) // is it a linkable class { writeMultiLineCodeLink(yyscanner,ol,md,memberName); addToSearchIndex(yyscanner,memberName); return; } // nothing found, just write out the word codifyLines(yyscanner,memberName); addToSearchIndex(yyscanner,memberName); }// generateMemLink static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol, const QCString &clName, bool /*typeOnly*/, const QCString &curr_class) { QCString className=clName; if (className.isEmpty()) return; ClassDef *cd=0; //MemberDef *md=0; //bool isLocal=false; className.stripPrefix("_"); cd = getClass(className); if (!cd && !curr_class.isEmpty()) { QCString cls = curr_class; QCString suffix = "::"; suffix+=clName; if (cls.right(suffix.length())==suffix) { cd = getClass(curr_class); } } while (cd) { //className.stripPrefix("_"); QCString temp(clName); temp.stripPrefix("_"); if (cd && cd->isLinkable()) // is it a linkable class { //if ((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ARCHITECTURECLASS) //{ // temp=VhdlDocGen::getClassName(cd); //} writeMultiLineCodeLink(yyscanner,ol,cd,temp); addToSearchIndex(yyscanner,className); return; } Definition *d = cd->getOuterScope(); if (d && d->definitionType()==Definition::TypeClass) { cd = toClassDef(d); } else { cd = 0; } } // nothing found, just write out the word codifyLines(yyscanner,clName); addToSearchIndex(yyscanner,clName); }// generateClasss or global link /*! counts the number of lines in the input */ static int countLines(yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; const char *p=yyextra->inputString; char c; int count=1; while ((c=*p)) { p++ ; if (c=='\n') count++; } if (p>yyextra->inputString && *(p-1)!='\n') { // last line does not end with a \n, so we add an extra // line and explicitly terminate the line after parsing. count++, yyextra->needsTermination=true; } return count; } static void endFontClass(yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (yyextra->currentFontClass) { yyextra->code->endFontClass(); yyextra->currentFontClass=0; } } static void startFontClass(yyscan_t yyscanner,const char *s) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (s==0) return; endFontClass(yyscanner); yyextra->code->startFontClass(s); yyextra->currentFontClass=s; } static void writeFont(yyscan_t yyscanner,const char *s,const QCString &text) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (s==0 || text.isEmpty()) return; //printf("writeFont(yyscanner,%d,\"%s\")\n",yyextra->yyLineNr,text); yyextra->code->startFontClass(s); yyextra->code->codify(text); yyextra->code->endFontClass(); } //---------------------------------------------------------------------------- static void appStringLower(QCString& qcs,const char* text) { qcs.resize(0); qcs.append(text); qcs=qcs.stripWhiteSpace(); } /* writes and links a port map statement */ static void codifyMapLines(yyscan_t yyscanner,const QCString &text) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (text.isEmpty()) return; QCString temp; //bool dot=false; int wordCounter=0; QCString ctemp; //printf("codifyMapLines(%d,\"%s\")\n",yyextra->yyLineNr,qPrint(text)); const char *p=text.data(); char c; bool done=false; while (!done) { //sp=p; while ((c=*p++) && c!='\n' && c!=':' && c != ' ' && c != '(' && c!='\0' && c!='\t') { if (c!=0x9) temp+=c; } if (c=='\0') return; if (!temp.isEmpty()) wordCounter++; if (!temp.isEmpty()) { // different kinds of component instantiations // xxx:yyy (generic/port) map( // xxx:(entity/component/configuration) yyy (generic/port) map( // xxx: entity yyy(zzz) (generic/port) map( if (wordCounter==2 || wordCounter==3) { QCString q=temp.lower(); // consider (upper/lower) cases if (q=="entity" || q=="component" || q=="configuration" || q=="port" || q=="generic") { generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,temp); } else { yyextra->PortMapComp=temp; generateClassOrGlobalLink(yyscanner,*yyextra->code,temp); } } else { generateMemLink(yyscanner,*yyextra->code,yyextra->currClass,temp); } } ctemp.fill(c,1); codifyLines(yyscanner,ctemp); ctemp.resize(0); temp.resize(0); }//while }//codifyMapLines /* * writes a function|procedure prototype and links the function|procedure name */ static void writeFuncProto(yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; QCString name,ret; VhdlDocGen::parseFuncProto(yyextra->funcProto,name,ret,false); if (name.isEmpty()) { codifyLines(yyscanner,yyextra->funcProto,yyextra->currClass); return; } StringVector qlist=split(yyextra->funcProto.str(),name.str()); QCString temp(qlist[0]); codifyLines(yyscanner,temp,yyextra->currClass); yyextra->funcProto.stripPrefix(temp); temp.resize(0); temp=yyextra->currClass; if (yyextra->isPackageBody) { temp.stripPrefix("_");// _{package body name} } const MemberDef *mdef=VhdlDocGen::findFunction(name,temp); if (mdef) { generateFuncLink(yyscanner,*yyextra->code,mdef); yyextra->funcProto.stripPrefix(name); codifyLines(yyscanner,yyextra->funcProto,yyextra->currClass); } else { codifyLines(yyscanner,yyextra->funcProto,yyextra->currClass); } }// writeFuncProto /* writes a process prototype to the output */ static void writeProcessProto(yyscan_t yyscanner) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; codifyLines(yyscanner,yyextra->funcProto,yyextra->currClass); yyextra->vhdlKeyDict.clear(); }// writeProcessProto /* writes a keyword */ static bool writeColoredWord(yyscan_t yyscanner,QCString& word ) { QCString qcs=word.lower(); const char *ss=VhdlDocGen::findKeyWord(qcs); if (ss) { writeFont(yyscanner,ss,word); return true; } return false; } //----------------------------------------------------------------------------------- struct VHDLCodeParser::Private { yyscan_t yyscanner; vhdlcodeYY_state state; }; VHDLCodeParser::VHDLCodeParser() : p(std::make_unique()) { vhdlcodeYYlex_init_extra(&p->state,&p->yyscanner); #ifdef FLEX_DEBUG vhdlcodeYYset_debug(1,p->yyscanner); #endif resetCodeParserState(); } VHDLCodeParser::~VHDLCodeParser() { vhdlcodeYYlex_destroy(p->yyscanner); } void VHDLCodeParser::resetCodeParserState() { p->state.vhdlKeyDict.clear(); } void VHDLCodeParser::parseCode(CodeOutputInterface &od, const QCString &className, const QCString &s, SrcLangExt, bool exBlock, const QCString &exName, FileDef *fd, int startLine, int endLine, bool inlineFragment, const MemberDef *memberDef, bool, const Definition *searchCtx, bool /* collectXRefs */) { yyscan_t yyscanner = p->yyscanner; struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd); if (s.isEmpty()) return; printlex(yy_flex_debug, true, __FILE__, fd ? qPrint(fd->fileName()): NULL); if (memberDef) { const ClassDef *dd=memberDef->getClassDef(); if (dd) yyextra->currClass=dd->name(); } resetCodeParserState(); yyextra->code = &od; yyextra->inputString = s.data(); yyextra->inputPosition = 0; yyextra->currentFontClass = 0; yyextra->needsTermination = false; yyextra->searchCtx = searchCtx; if (startLine!=-1) yyextra->yyLineNr = startLine; else yyextra->yyLineNr = 1; if (endLine!=-1) yyextra->inputLines = endLine+1; else yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1; // yyextra->theCallContext.clear(); yyextra->exampleBlock = exBlock; yyextra->exampleName = exName; yyextra->sourceFileDef = fd; bool cleanupSourceDef = false; if (exBlock && fd==0) { // create a dummy filedef for the example yyextra->sourceFileDef = createFileDef("",exName); cleanupSourceDef = true; } if (yyextra->sourceFileDef) { setCurrentDoc(yyscanner,"l00001"); } yyextra->currentDefinition = 0; yyextra->currentMemberDef = 0; yyextra->vhdlMember=0; if (!yyextra->exampleName.isEmpty()) { yyextra->exampleFile = convertNameToFile(yyextra->exampleName+"-example"); } yyextra->includeCodeFragment = inlineFragment; startCodeLine(yyscanner); if (!yyextra->lexInit) { VhdlDocGen::init(); yyextra->lexInit=true; } /*int iLine=*/countLines(yyscanner); vhdlcodeYYrestart( 0, yyscanner ); BEGIN( Bases ); vhdlcodeYYlex(yyscanner); if (yyextra->needsTermination) { endCodeLine(yyscanner); } if (cleanupSourceDef) { // delete the temporary file definition used for this example delete yyextra->sourceFileDef; yyextra->sourceFileDef=0; } yyextra->startCode=false; // write the tooltips TooltipManager::instance().writeTooltips(od); printlex(yy_flex_debug, false, __FILE__, fd ? qPrint(fd->fileName()): NULL); } #if USE_STATE2STRING #include "vhdlcode.l.h" #endif