/****************************************************************************** * * Copyright (C) 1997-2010 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 VHDL subset * written by M. Kreis * supports VHDL-87/93 * does not support VHDL-AMS ******************************************************************************/ %{ // global includes #include #include #include #include #include #include #include /* --------------------------------------------------------------- */ // local includes #include "vhdlscanner.h" #include "vhdlcode.h" #include "vhdldocgen.h" #include "message.h" #include "config.h" #include "doxygen.h" #include "util.h" #include "language.h" #include "commentscan.h" #include "index.h" #include "definition.h" #include "searchindex.h" #include "outputlist.h" /* --------------------------------------------------------------- */ //#define theTranslator_vhdlType theTranslator->trVhdlType #define theTranslator_vhdlType VhdlDocGen::getVhdlType static QStringList qrl; static int openGroups; static ParserInterface *g_thisParser; static const char * inputString; static int inputPosition; static int startComment = 0; static QFile inputFile; static QCString inbuf; static Entry* global_root = 0; static Entry* current_root = 0; static Entry* current = 0; static Entry* previous = 0; static Entry* functionEntry = 0; static Entry* lastEntity = 0; static Entry* lastCompound = 0; static int genPort = 0; static QCString yyFileName; static int iFuncLine = 1; static bool g_inputFromFile ; static bool g_lexInit = FALSE; static int isBody=0; static int isFunc=0; static int yyLineNr = 1; static char * g_buf = 0; static uint g_bufSize = 0; static int iTextCounter = 0; static int iCounter = 0; static int bropen = 0; static int scantype = 0; static int g_lastCommentContext = 0; static bool docBlockAutoBrief; static char docBlockTerm; static int iDocLine = -1; //#define YY_A_INTERACTIVE 1 #define YY_NEVER_INTERACTIVE 1 //----------------------------------------------------------------------------- static void parserInit(); static void deleteSpecChars(char* str,char *buf); static void handleCommentBlock(const QCString &doc,bool brief); static void newEntry(); static void initEntry(Entry *e); static void addSubEntry(Entry* root, Entry* e) { if (e==0 || root==0) return; //if (isPrevDoc) //{ // e->brief=prevDocEntry.brief; // e->briefLine=prevDocEntry.briefLine; // prevDocEntry.reset(); // isPrevDoc=FALSE; //} root->addSubEntry(e); } static void bufferClear() { int j; for (j=0;j g_bufSize) { char *pTmp = (char*)realloc(g_buf,iCounter+llen+2048); if (pTmp) { g_buf = pTmp; } else { fprintf(stderr,"\n not enough memory for realloc\n"); return; } } while (llen>0) { g_buf[iCounter]=*word++; iCounter++; llen--; } g_buf[iCounter]='\0'; } static void getBufText(QCString& qc,int start) { while (start < iCounter) { qc+=(g_buf[start]); start++; } } static void lineCount() { for ( const char* c = yytext ; *c ; ++c ) { yyLineNr += (*c == '\n') ; } } static void deleteSpecChars(char* str,char *buf) { while (*str) { if ((*str == '\t') || (*str == '\n') || (*str == '\r') || (*str == ' ')) { *str++; } else { *buf++ = *str++; } } *buf='\0'; } void getType(Entry* p,char* text) { QCString name(text); name=name.stripWhiteSpace(); if (stricmp(name.data(),"signal" )==0) { p->spec=VhdlDocGen::SIGNAL; } else if (stricmp(name.data(),"type" )==0) { p->spec=VhdlDocGen::TYPE; } else if (stricmp(name.data(),"subtype" )==0) { p->spec=VhdlDocGen::SUBTYPE; } else if (stricmp(name.data(),"constant" )==0) { p->spec=VhdlDocGen::CONSTANT; } else if (stricmp(name.data(),"attribute" )==0) { p->spec=VhdlDocGen::ATTRIBUTE; } else if (stricmp(name.data(),"function" )==0) { p->spec=VhdlDocGen::FUNCTION; } else if (stricmp(name.data(),"procedure" )==0) { p->spec=VhdlDocGen::PROCEDURE; } else if (stricmp(name.data(),"units" )==0) { p->spec=VhdlDocGen::UNITS; } else if (name.contains("shared",false) && name.contains("variable",false)) { p->spec=VhdlDocGen::SHAREDVARIABLE; } else if (stricmp(name.data(),"file" )==0) { p->spec=VhdlDocGen::VFILE; } else if (stricmp(name.data(),"group" )==0) { p->spec=VhdlDocGen::GROUP; } else if (stricmp(name.data(),"alias" )==0) { p->spec=VhdlDocGen::ALIAS; } else { err("wrong type"); } p->section=Entry::VARIABLE_SEC; } //------------------------------------------------------------------------- /* * adds signals found in entities|records|units */ void addSignals(const char* str,int line, Entry *e,const char *comment=0) { //printf("===> addSignals (%s) comment='%s'\n",str,comment); QList ql; QCString bufio; ql.setAutoDelete(TRUE); VhdlDocGen::getSigName(ql,str,bufio); int count = ql.count(); QCString brief = current->brief; QCString doc = current->doc; Entry *tmpEntry = current; current = new Entry; initEntry(current); handleCommentBlock(comment,TRUE); if (!current->brief.isEmpty()) { if (doc.isEmpty()) { doc = brief; } else if (!brief.isEmpty()) { doc = brief + "

" + doc; } brief = current->brief; } delete current; current = tmpEntry; current->brief.resize(0); current->doc.resize(0); if (genPort!=3) // not a unit { for (int k=1;kdata(),ql.at(k)->data()); Entry *pTemp=new Entry; initEntry(pTemp); pTemp->startLine = line; pTemp->bodyLine = line; pTemp->name = ql.at(k)->data(); pTemp->section = Entry::VARIABLE_SEC; pTemp->brief = brief; pTemp->doc = doc; pTemp->mGrpId = current->mGrpId; // copy member group id QCString stSpec = ql.at(0)->data(); if (genPort==1) // found port { pTemp->spec = VhdlDocGen::PORT; stSpec.stripPrefix(bufio.data()); stSpec=stSpec.stripWhiteSpace(); pTemp->args = stSpec; pTemp->type = bufio; addSubEntry(e,pTemp); } else if (genPort==2) // found record { pTemp->spec = VhdlDocGen::RECORD; pTemp->type = stSpec; pTemp->name.prepend(VhdlDocGen::getRecordNumber()); delete current; current = new Entry(*pTemp); // make a deep copy of pTemp newEntry(); // add it to lastCompound and make a new current delete pTemp; } else { pTemp->spec = VhdlDocGen::GENERIC; pTemp->type = stSpec; addSubEntry(e,pTemp); } }// for } else // found a unit { Entry *pTemp=new Entry; initEntry(pTemp); QCString tt(str); QStringList ql=QStringList::split("=",tt,FALSE); pTemp->spec = VhdlDocGen::UNITS; pTemp->section = Entry::VARIABLE_SEC; pTemp->startLine = line; pTemp->bodyLine = line; pTemp->brief = brief; // adds brief description to the unit member pTemp->doc = doc; // adds doc to the unit member pTemp->type = ql[1]; pTemp->name = ql[0].stripWhiteSpace(); pTemp->name.prepend(VhdlDocGen::getRecordNumber()); delete current; current = new Entry(*pTemp); // make a deep copy newEntry(); // add it to lastCompound delete pTemp; } } /* * this function parses a process prototype * and adds the signal to the process */ static void parseProcessProto() { QStringList ql; QCString qcs; bool sem=FALSE; //Entry* ppEntry=new Entry; //ppEntry->fileName=yyFileName; //processEntry=ppEntry; QCString name; scantype=0; getBufText(qcs,0); if (qcs.contains('(') != qcs.contains(')')) return; VhdlDocGen::deleteAllChars(qcs,'\n'); VhdlDocGen::parseProcessProto(qcs,name,ql); current->section=Entry::FUNCTION_SEC; //current->stat=TRUE; current->spec=VhdlDocGen::PROCESS; current->startLine=iFuncLine; current->bodyLine=iFuncLine; current->fileName=yyFileName; if (!name.isEmpty()) { current->name=name.stripWhiteSpace(); } else // found an anonymous process, so we add a generated name { current->name=VhdlDocGen::getProcessNumber(); } current->args+=" ( "; if (!ql.isEmpty()) { QValueList::Iterator iter = ql.begin(); for ( ; iter != ql.end(); ++iter) { if (sem) { current->args+=','; } Argument *arg=new Argument; arg->name=((QCString)*iter).stripWhiteSpace(); current->argList->append(arg); current->args+=(QCString)*iter; sem = TRUE; } } current->args+=" ) "; bufferClear(); }//parseProcessProto /* * parses a function|procedure protoype */ static void parseFunctionProto() { QCString name,ret,qcs,temp; bool sem=FALSE; QList ql; ql.setAutoDelete(TRUE); getBufText(qcs,0); if (qcs.contains('(') != qcs.contains(')')) return; // function without a prototype if (qcs.contains("function",FALSE)==0 && qcs.contains("procedure",FALSE)==0) return; qcs=qcs.stripWhiteSpace(); temp=qcs.lower(); if (temp.stripPrefix("impure")) { current->exception="impure"; qcs=qcs.remove(0,6); } else if (temp.stripPrefix("pure")) { current->exception="pure"; qcs=qcs.remove(0,4); } VhdlDocGen::parseFuncProto(qcs.data(),ql,name,ret); //printf("parseFuncProto(%s)=%s,%s\n",qcs.data(),name.data(),ret.data()); VhdlDocGen::deleteAllChars(name,';'); current->name=name; current->startLine=iFuncLine; current->bodyLine=iFuncLine; int count = ql.count(); current->args+" ( "; for (int k=0;kargs+=","; } Argument *arg=new Argument; Argument *hh=(Argument*)ql.at(k); arg->name=hh->name; arg->type=hh->type; arg->defval=hh->defval; arg->attrib=hh->attrib; current->argList->append(arg); current->args+=hh->name; sem=TRUE; } current->args+" )"; if (!ret.isEmpty()) current->spec=VhdlDocGen::FUNCTION; else current->spec=VhdlDocGen::PROCEDURE; current->section=Entry::FUNCTION_SEC; current->type=ret; //addSubEntry(ee,ppEntry); if (lastCompound) { lastCompound->addSubEntry(current); current = new Entry; initEntry(current); } else { newEntry(); } bufferClear(); }//parseFunctionProto static Entry* getEntryAtLine(const Entry* ce,int line) { EntryListIterator eli(*ce->children()); Entry *found=0; Entry *rt; for (;(rt=eli.current());++eli) { if (rt->bodyLine==line) { found=rt; } // if if (!found) { found=getEntryAtLine(rt,line); } } return found; }// getEntryAtLine //------------------------------------------------------------------------- void parserInit() { iCounter=0; iTextCounter=0; yyLineNr=1; current=0; previous=0; isFunc=0; isBody=0; scantype=0; //pEntry=0; //pp=0; lastCompound=0; lastEntity=0; bropen=0; openGroups=0; iDocLine=-1; //isPrevDoc=FALSE; //prevDocEntry.reset(); qrl.clear(); if (!g_lexInit) { VhdlDocGen::init(); } g_bufSize=inputFile.size()+1024; if (g_buf==0) free(g_buf); g_buf=(char*)(calloc(g_bufSize,sizeof(char))); if (g_buf==0) { fprintf(stderr,"\n not enough memory"); return; } g_buf[g_bufSize-1]='\0'; } bool VHDLLanguageScanner::needsPreprocessing(const QCString &) { return FALSE; } void VHDLLanguageScanner::resetCodeParserState() { } #undef YY_INPUT #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); static int yyread(char *buf,int max_size) { int c=0; if (g_inputFromFile) { c = inputFile.readBlock(buf,max_size); if (c==-1) yy_fatal_error("input in flex scanner failed"); } else { while ( c < max_size && inputString[inputPosition] ) { *buf = inputString[inputPosition++] ; c++; buf++; } } return c; } #if 0 /* * adds a text line description [--#] to the the previous type */ static void addOneTextLine(QCString& ss ) { Entry* pTemp=0; if (current && current->bodyLine==yyLineNr) pTemp=current; //else if (pEntry && pEntry->bodyLine==yyLineNr) // pTemp=pEntry; else pTemp=getEntryAtLine(current_root,yyLineNr) ; if (pTemp) { ss=ss.stripWhiteSpace(); ss.stripPrefix("--!"); pTemp->brief=ss; pTemp->briefLine=yyLineNr; } } #endif %} /* start command character */ /* -------------- VHDL SECTION -----------------------------------*/ B [ \t] CR [\r\n] BR [ \t\n\r] DIGIT [0-9] LOWER_CASE_LETTER [a-z] UPPER_CASE_LETTER [A-Z] LETTER [a-zA-Z_0-9] SPACE_CHARACTER [ \t] SPECIAL_CHARACTER [#&'()*+,\-\./:;<=>_|] OTHER_SPECIAL_CHARACTER [~!$ยง%?@\[\\\]^{}] BASIC_GRAPHIC_CHARACTER {UPPER_CASE_LETTER}|{DIGIT}|{SPECIAL_CHARACTER}|{SPACE_CHARACTER} GRAPHIC_CHARACTER {BASIC_GRAPHIC_CHARACTER}|{LOWER_CASE_LETTER}|{OTHER_SPECIAL_CHARACTER} EXTENDED_CHARACTER [\\]{GRAPHIC_CHARACTER}*[\\] NAME ({LETTER}[a-zA-Z0-9_.]*)|{EXTENDED_CHARACTER} STRING_LITERAL \"{GRAPHIC_CHARACTER}*\" FUNCNAME ([a-zA-Z"][*+\-_a-zA-Z0-9"\/=<>]*)|{EXTENDED_CHARACTER} DIGITS [0-9]+|[0-9]+"."[0-9]+|[0-9]+"#"[0-9_a-fA-F\+\.]+"#" COMMENT "--"[^\n]* LABELID [a-z_A-Z][^\;]*";"({B}*{COMMENT})* PROTO [ (]* TEXTT "--"[^\/\@\*\#][^\n]* PROC ("function"|"procedure") ENDE ({BR}*("end"){BR}*{PROC}*{BR}*[;]{1}) ENDEFF ("if"|"case"|"loop"|"generate"){BR}*[;] ENDE3 ({BR}*("end"){BR}*{PROC}*{BR}*{FUNCNAME}{BR}*[;])|{ENDE} ENDFUNC {B}*"end"{BR}*{PROC}*{BR}*{FUNCNAME}{BR}*[;] FUNCIMPURE "impure"|"pure" FUNCPROC ^{B}*{FUNCIMPURE}*{BR}*("function"|"procedure"){B}* ARCHITECTURE ("architecture"){BR}+{NAME}{BR}*("of") /* Removed due to bug 538239 POST "postponed" PROCESS ({BR}*{FUNCNAME}{B}*[:]{BR}*({POST}{BR}+)?("process"){BR}*{PROTO})|("process"){BR}*("("){BR}*{PROTO}|[^a-zA-Z]("process"){CR}|[^a-zA-Z]("process"){BR}+("is") */ PROCESS ({B}*{FUNCNAME}{B}*:{BR}*)?({B}*("postponed"){BR}+)?{B}*("process"){BR}*{PROTO} ENDPROCESS ("end"){BR}*("postponed")*("process"){BR}*{FUNCNAME}*{BR}*[;] LIBUSE ^{B}*("use"|"library"){BR}+ ENTITY ^{B}*("component"|"entity"|"package"){BR}+ PBODY ("package"){B}+("body"){BR}+{NAME} SHARED ("shared"){BR}+("variable") SIGTYPES ^{B}*({SHARED}|"alias"|"file"|"group"|"subtype"|"type"|"constant"|"attribute"|"signal"|"units"){BR}+ CONFIG ("configuration"){BR}+{NAME}{BR}*("of"){BR}+{NAME}{BR}+"is" ALLTYPESMAP {B}*[_a-zA-ZA_Z0-9.() ]*{B}* MAPCOMPONENT ({ALLTYPESMAP}{BR}*[:]{BR}*("component"|"configuration")*{ALLTYPESMAP}{BR}*{TEXTT}*{BR}*("port"|"generic"){BR}*("map"){BR}*("("){1}) MAPCOMPONENT1 ({ALLTYPESMAP}{BR}*[:]{BR}*("entity"){BR}*{ALLTYPESMAP}{BR}*("port"|"generic"){BR}*("map"){BR}*("("){1}) BRACEOPEN [(]{1} BRACECLOSE [)]{1} ALLID [^;()\t ] /* VHDL 2001 */ ENDPROTECTED ("end"{BR}+"protected"{BR}+{NAME}{BR}*";")|("end"{BR}+"protected"{BR}*";") ENDPROTECEDBODY "end"{BR}+"protected"{BR}+"body"{BR}+{NAME} %option noyywrap /* language parsing states */ %x Start %x Comment %x FindTypeName %x ParseType %x ParseRecord %x ParseUnits %x ParseProcess %x ParseFunc %x FindName %x FindEntityName %x FindGenPort %x FindTypes %x FindSigName %x FindFuncName %x FindBegin %% {ENDPROTECTED}|{ENDPROTECEDBODY} { lineCount(); } {CONFIG} { // found configuration QCString qcs(vhdlscanYYtext); current->name=VhdlDocGen::getIndexWord(qcs,1); current->type=VhdlDocGen::getIndexWord(qcs,3); current->startLine=yyLineNr; current->bodyLine=yyLineNr; current->section=Entry::VARIABLE_SEC; current->spec=VhdlDocGen::CONFIG; current->args="configuration"; newEntry(); BEGIN(Start); } {SIGTYPES} { // found type constant|type|attribute and so on.. bropen=0; lineCount(); bufferClear(); //pEntry=current; getType(current,yytext); current->bodyLine=yyLineNr; if (current->spec==VhdlDocGen::UNITS) { //addSubEntry(current,pEntry); current->startLine=yyLineNr; current->bodyLine=yyLineNr; newEntry(); // adds the unit to the lastCompound genPort=3; BEGIN(ParseRecord); } else { BEGIN(FindTypeName); } } {ARCHITECTURE} { //found architecure lineCount(); bropen=0; bufferClear(); isBody=0; lastCompound = current; QCString curName=VhdlDocGen::getIndexWord(yytext,1); current->section=Entry::CLASS_SEC; //Entry::CLASS_SEC; current->spec=VhdlDocGen::ARCHITECTURE; current->protection=Private; current->name=curName; current->fileName=yyFileName; current->startLine=yyLineNr; current->bodyLine=yyLineNr; //printf("-> Architecture at line %d\n",yyLineNr); BEGIN(FindName); } {PROCESS} { //found process lineCount(); iFuncLine=yyLineNr; bropen=0; //printf("--> Process: line=%d\n",yyLineNr); bufferClear(); addText(yytext,yyleng); QCString qcs(yytext); if (qcs.contains('(')) { bropen=1; scantype=2; BEGIN(ParseType); } else { // iFuncLine--; parseProcessProto(); BEGIN(ParseProcess); } } {LIBUSE}{BR}* { // found library or package bropen=0; bufferClear(); isBody=0; QCString qcs=QCString(yytext); // lowerString(qcs); qcs=qcs.stripWhiteSpace(); if (stricmp(qcs.data(),"use")==0) { current->spec=VhdlDocGen::USE; current->type="package"; } else { current->spec=VhdlDocGen::LIBRARY; current->type="library"; } current->section=Entry::VARIABLE_SEC; current->bodyLine=yyLineNr; lineCount(); BEGIN(FindName); } {FUNCPROC} { // found a new function|procedure lineCount(); iFuncLine=yyLineNr; bropen=0; bufferClear(); isFunc=1; addText(yytext,yyleng); BEGIN(FindFuncName); } {ENTITY} { // found entity|component|package lineCount(); //printf("--> Entity at line %d\n",yyLineNr); bropen=0; bufferClear(); QCString word(yytext); word=word.lower(); word=word.stripWhiteSpace(); if (strcmp(word.data(),"entity")==0) { isBody=0; scantype=0; lastCompound=0; current->section=Entry::CLASS_SEC; current->spec=VhdlDocGen::ENTITY; current->protection=Public; current->bodyLine=yyLineNr; current->fileName=yyFileName; lastEntity = current; } else if (strcmp(word.data(),"component")==0) { current->section=Entry::VARIABLE_SEC; // current->stat=TRUE; current->spec=VhdlDocGen::COMPONENT; current->bodyLine=yyLineNr; scantype=1; } else if (strcmp(word,"package")==0) { isBody=0; scantype=0; lastCompound = current; current->section=Entry::CLASS_SEC; current->spec=VhdlDocGen::PACKAGE; current->protection=Package; //VhdlDocGen::PACKAGE; current->bodyLine=yyLineNr; current->fileName=yyFileName; } else err("\n found wrong component at line [%d]",yyLineNr); BEGIN(FindEntityName); } {MAPCOMPONENT}|{MAPCOMPONENT1} { // found component instantiation // lineCount(); QCString type; QCString tt(yytext); QRegExp regg("[\\s:.()-]"); QStringList qsl=QStringList::split(regg,tt,false); // consider upper/lower-case letters QStringList qsltemp=QStringList::split(regg,tt.lower(),false); int index=qsltemp.findIndex(QCString("entity"))+1; index+=qsltemp.findIndex(QCString("component"))+1; index+=qsltemp.findIndex(QCString("configuration"))+1; int len=qsltemp.count(); current->spec=VhdlDocGen::COMPONENT_INST; current->section=Entry::VARIABLE_SEC; current->startLine=yyLineNr; current->bodyLine=yyLineNr; if (index!=0 && tt.contains(')')==0) // found component instantiation xxx: configuration/component/entity yyy { current->type=(QCString)qsl[len-3]; } else if (index!=0 && tt.contains(')')) // found component instantiation xxx: entity www.yyy(zzz) { current->type=(QCString)qsl[len-4]; } else { current->type=(QCString)qsl[1]; // found component instantiation xxx:yyy } current->name=QCString(qsl[0]); if (lastCompound) { if (!VhdlDocGen::foundInsertedComponent(current->type,lastCompound)) { BaseInfo *bb=new BaseInfo(current->type,Public,Normal); lastCompound->extends->append(bb); } lastCompound->addSubEntry(current); current = new Entry; initEntry(current); } else { newEntry(); } lineCount(); } {CR}* { lineCount(); addText(yytext,yyleng); BEGIN(Start); } [^;()] { // eat process body lineCount(); BEGIN(ParseProcess); } {ENDPROCESS} { // find end of process lineCount(); current->endBodyLine=yyLineNr; //printf("Process: start=%d end=%d\n",current->bodyLine,current->endBodyLine); if (lastCompound) { lastCompound->addSubEntry(current); current = new Entry; initEntry(current); } else { newEntry(); } BEGIN(Start); } {BR}* { lineCount(); } {B}*[a-z_][^\n;]* { // parse record|unit body lineCount(); QCString zz(yytext); addSignals(zz.data(),yyLineNr,current); BEGIN(ParseUnits); } {NAME} { // found entity|architecture|component name lineCount(); QCString qcs(yytext); qcs=qcs.stripWhiteSpace(); if (current->spec==VhdlDocGen::USE || current->spec==VhdlDocGen::LIBRARY) { int j=qcs.length(); int i=qcs.find("."); if (i>0) qcs=qcs.right(j-i-1); i=qcs.find("."); if (i>0) qcs=qcs.left(i); /* -- Consider the case we have more than one entity in one file.Each entity has its own package/library -- declaration. In this case package yyy will be added [with newEntry()] to architecture aaa !! instead to entity -- bbb. We must place these constructs to current_root and the function mapLibPackage() will finish the rest. -- package xxx; -- entity aaa -- .... -- end entity aaa; -- architecture aaa -- ... -- end architecture aaa; -- package yyy; -- entity bbb; */ current->name=qcs; Entry *copy=new Entry(*current); current->reset(); addSubEntry(current_root,copy); // insert into entry list with mapLibPackage() } else if (current->spec==VhdlDocGen::ARCHITECTURE) { //current->name+=qcs.lower(); current->name.prepend(qcs+"::"); //if (lastEntity) //{ // inherit private inheritance relation between entity and architecture //if (!VhdlDocGen::foundInsertedComponent(current->name,lastEntity)) //{ // BaseInfo *bb=new BaseInfo(current->name,Private,Normal); // lastEntity->extends->append(bb); //} //} } else if (current->spec==VhdlDocGen::PACKAGE_BODY) { current->name+=qcs; } else { current->name+=qcs; } if (!(current->spec==VhdlDocGen::USE || current->spec==VhdlDocGen::LIBRARY)) newEntry(); BEGIN(Start); } {FUNCNAME} { // found name of a process|function|procedure lineCount(); addText(yytext,yyleng); BEGIN(ParseType); } {NAME}{BR}* { lineCount(); current->name=QCString(yytext); BEGIN(ParseType); } ("is"){BR}+("protected"){BR}+("body") {lineCount(); BEGIN(Start); } ("is"){BR}+("protected"){BR}+ { lineCount(); current->section=Entry::VARIABLE_SEC; current->spec=VhdlDocGen::TYPE; current->type="protected"; newEntry(); BEGIN(Start); } ("is"){BR}*("record") { // find record lineCount(); if (isFunc) { BEGIN(Start); } genPort=2; current->section=Entry::VARIABLE_SEC; current->spec=VhdlDocGen::RECORD; addText(yytext,yyleng); newEntry(); // adds the record to the last compound BEGIN(ParseRecord); } {BR}* { lineCount(); } ("end"){BR}*("record"){BR}*{LETTER}*{BR}*[;]|("end"){BR}*("units"){BR}*[;] { lineCount(); genPort=0; bufferClear(); BEGIN(Start); } [a-z_A-Z0-9][^\n;]*";"({B}*{COMMENT})* { // parse record body lineCount(); QCString comment; QCString zz(yytext); VhdlDocGen::deleteAllChars(zz,';'); //delete ; in unit construct if (zz.contains("--!")) { QStringList ql=QStringList::split("--!",zz,FALSE); comment = ql[1]; zz = ql[0]; } else if (zz.contains("--")) { QStringList ql=QStringList::split("--",zz,FALSE); zz = ql[0]; } initEntry(current); addSignals(zz,yyLineNr,current,comment); addText(yytext,yyleng); BEGIN(ParseRecord); } {BR}+("is"){BR}+|{BR}+("is"){B}*"--" { // found a new function in an architecture ? addText(yytext,yyleng); lineCount(); QCString ttt; bool bb=TRUE; getBufText(ttt,0); if (ttt.contains("--")) { unput('-');unput('-'); VhdlDocGen::deleteCharRev(ttt,'-'); VhdlDocGen::deleteCharRev(ttt,'-'); } if (ttt.contains('(') != ttt.contains(')')) { bb=FALSE; } bool ss = VhdlDocGen::isFunctionProto(ttt); //printf("VhdlDocGen::isFunctionProto(%s)=%d\n",ttt.data(),ss); if (ss && bb) { bufferClear(); addText(ttt.data(),ttt.length()); functionEntry=0; //eFuncBody=new Entry; ::parseFunctionProto(); #if 0 EntryListIterator eli(*eFuncBody->children()); Entry *rrt=eli.current(); if (current && (current->spec==VhdlDocGen::ARCHITECTURE && rrt)) { Entry *ep=new Entry(*rrt); addSubEntry(current,ep); isBody=1; } if (rrt) { Entry *ef=VhdlDocGen::findFunction(current_root,rrt); if (ef) { ef->bodyLine=iFuncLine; functionEntry=ef; } else if ((current->spec==VhdlDocGen::PACKAGE_BODY))//VhdlDocGen::Package_Body)) { Entry *ep=new Entry(*rrt); addSubEntry(current,ep); ep->bodyLine=iFuncLine; functionEntry = ep; } } delete eFuncBody; eFuncBody=0; #endif } bufferClear(); BEGIN(ParseType); } [^;()\t ] { lineCount(); addText(yytext,yyleng); BEGIN(ParseType); } {BRACEOPEN} { lineCount(); bropen++; addText(yytext,yyleng); BEGIN(ParseType); } {BRACECLOSE} { lineCount(); bropen--; addText(yytext,yyleng); if (bropen==0 && scantype==2) // process { ::parseProcessProto(); BEGIN(ParseProcess); } // if else { BEGIN(ParseType); } } {ENDE}|{ENDFUNC} { // found end of function|process QRegExp regg("[\\s;]"); lineCount(); QCString tt(yytext); tt=tt.lower(); QStringList ql=QStringList::split(regg,tt,FALSE); int index=ql.findIndex(QCString("if"))+1; index+=ql.findIndex(QCString("case"))+1; index+=ql.findIndex(QCString("loop"))+1; index+=ql.findIndex(QCString("generate"))+1; bufferClear(); if (index==0) { if (isFunc) { Entry* pFunc=getEntryAtLine(current_root,iFuncLine); if (pFunc && pFunc->section==Entry::FUNCTION_SEC) { pFunc->endBodyLine=yyLineNr; } isFunc=0; BEGIN(Start); } } } [^;()] { // eat process body lineCount(); BEGIN(ParseFunc); } {ENDE3} { QRegExp regg("[\\s;]"); lineCount(); QCString tt(yytext); tt=tt.lower(); QStringList ql=QStringList::split(regg,tt,FALSE); int index=ql.findIndex(QCString("if"))+1; index+=ql.findIndex(QCString("case"))+1; index+=ql.findIndex(QCString("loop"))+1; index+=ql.findIndex(QCString("generate"))+1; bufferClear(); if (index==0 && isFunc) { Entry* pFunc=getEntryAtLine(current_root,iFuncLine); if (pFunc && pFunc->section==Entry::FUNCTION_SEC) { pFunc->endBodyLine=yyLineNr; } isFunc=0; BEGIN(Start); } } ";" { lineCount(); addText(yytext,yyleng); if (bropen==0 && !(isFunc==1 && isBody==1) ) { if (isFunc) { parseFunctionProto(); bufferClear(); if (lastCompound && lastCompound->spec==VhdlDocGen::PACKAGE) { isFunc=0; BEGIN(Start); } else { BEGIN(ParseFunc); } }//if else { QCString qcs; getBufText(qcs,0); qcs=qcs.stripWhiteSpace(); current->section=Entry::VARIABLE_SEC; current->type+=qcs.data(); if ((current->spec==VhdlDocGen::SIGNAL || current->spec==VhdlDocGen::CONSTANT || current->spec==VhdlDocGen::TYPE || current->spec==VhdlDocGen::SUBTYPE || current->spec==VhdlDocGen::SHAREDVARIABLE ) && qcs.stripPrefix(",")) { QList ql; ql.setAutoDelete(TRUE); QCString buffer; if (current->spec==VhdlDocGen::SUBTYPE || current->spec==VhdlDocGen::TYPE ) { VhdlDocGen::getSigTypeName(ql,qcs.data(),buffer); } else { VhdlDocGen::getSigName(ql,qcs.data(),buffer); } QCString doc = current->doc; QCString brief = current->brief; if (ql.count()>0) { for (uint j=1;jtype += ql.at(0)->data(); ppt->section = Entry::VARIABLE_SEC; ppt->spec = current->spec; ppt->name += ql.at(j)->data(); ppt->bodyLine = yyLineNr; ppt->startLine = yyLineNr; ppt->brief = brief; ppt->doc = doc; if (lastCompound) { lastCompound->addSubEntry(ppt); } else { current->addSubEntry(ppt); } } current->type=ql.at(0)->data(); ql.clear(); } } if (lastCompound) { lastCompound->addSubEntry(current); current = new Entry; initEntry(current); } else { newEntry(); } isFunc=0; bufferClear(); BEGIN(Start); } } else { BEGIN(ParseType); } } {TEXTT} { lineCount(); BEGIN(ParseType); } {BR}* { lineCount(); addText(yytext,yyleng); BEGIN(ParseType); } {NAME} { // found name of an entity/architecture/package lineCount(); QCString qcs(yytext); qcs=qcs.stripWhiteSpace(); qcs=qcs.lower(); if (strcmp(qcs.data(),"body")==0) // found package body { current->spec=VhdlDocGen::PACKAGE_BODY; current->section=Entry::CLASS_SEC; current->protection=Protected; current->name+=QCString("_"); isBody=1; BEGIN(FindName); } else if (scantype==1) // found a component { QCString qq(yytext); qq=qq.stripWhiteSpace(); //qq=qq.lower(); current->name=qq; if (lastCompound) { if (lastCompound->spec==VhdlDocGen::PACKAGE) { if (!VhdlDocGen::foundInsertedComponent(qq,lastCompound)) { BaseInfo *bb=new BaseInfo(qq,Private,Normal); lastCompound->extends->append(bb); } } lastCompound->addSubEntry(current); current = new Entry; initEntry(current); } else { newEntry(); } BEGIN(Start); } else { QCString qq(yytext); qq=qq.stripWhiteSpace(); current->name=qq; newEntry(); //QCString qreal=QCString(yytext); BEGIN(Start); } } {B}*("generic"|"port"){BR}*[(]+ { // found generic|port in entity QCString genp(yyleng+1); deleteSpecChars(yytext,genp.data()); VhdlDocGen::deleteCharRev(genp,'('); if (stricmp(genp.data(),"port" )==0) { genPort=1; } else { genPort=0; } bropen=1; bufferClear(); lineCount(); BEGIN(FindSigName); } {BRACECLOSE} { lineCount(); bropen--; addText(yytext,yyleng); if (bropen==0) { bufferClear(); BEGIN(Start); } else { BEGIN(FindSigName); } } {LABELID} { // found signals in entity QCString line(yytext); // note that line can be something like: // "var1, var2, var3 : in std_logic_vector(8 downto 0); --! Some comment" // but also // "var4 --! Some comment // );" // which marks the end of a port // and also // "-- Some comment // var1 : in std_logic;" //printf("--> labelid='%s'\n",line.data()); QStringList ql; QCString comment; int openCount=line.contains('('); int closeCount=line.contains(')'); int semi = line.find(';'); int pos = line.find("--"); int pos1 = line.find("--!"); if (pos!=-1 && pos signal: line='%s'\n",line.data()); if (semi!=-1 && pos!=-1) { int eol = line.findRev('\n'); //printf("pos=%d eol=%d\n",pos,eol); if (eol>=pos+2) { QRegExp re("\\n[\\s]*--!"); // comment continuation comment=line.mid(pos+2,eol-pos-2); //printf("Comment: '%s'\n",comment.data()); int p,l; while ((p=re.match(comment,0,&l))!=-1) { comment.remove(p,l); } line=line.left(pos)+line.right(line.length()-eol); } else { comment=line.mid(pos+2); line=line.left(pos); } comment.stripWhiteSpace(); // must subtract "(" and ")" in comments because they are used for determining the // end of a port/generic construct openCount-=comment.contains('('); closeCount-=comment.contains(')'); if (!comment.stripPrefix("!")) // not a special comment { comment.resize(0); } } else { //printf("no ; or --: pos=%d semi=%d\n",pos,semi); } int diff=openCount-closeCount; if (diff<0) { VhdlDocGen::deleteCharRev(line,')'); } if (scantype!=1) // not a component { addText(yytext,yyleng); addSignals(line,yyLineNr,lastEntity,comment); } lineCount(); if ((bropen+openCount-closeCount)==0) { bufferClear(); BEGIN(Start); } } {BRACEOPEN} { lineCount(); bropen++; addText(yytext,yyleng); } {CR} { lineCount(); addText(yytext,yyleng); //BEGIN(FindSigName); } <*>^{B}*("for ")[^;]* { //printf("\n found for[%s] [%d]",yytext,yyLineNr); lineCount(); } <*>{DIGITS} { // found digit addText(yytext,yyleng); lineCount(); } <*>{STRING_LITERAL} { // Make sure string literals get transfered to the output // We have to match these because the comment characters (--) // can exist inside a string literal. // We shouldn't have to call lineCount because newlines // are not allowed inside string literals addText(yytext,yyleng); } /* <*>{BR}*"--!"{B}*"@}" { // end group if (current) { Entry *pg=new Entry; addSubEntry(current,pg); pg->startLine=yyLineNr; pg->name="endgroup"; } lineCount(); } <*>{BR}*"--!"{B}*"@{" { // start group if (current) { Entry *pg=new Entry; addSubEntry(current,pg); pg->startLine=yyLineNr; pg->name="startgroup"; } lineCount(); } */ <*>{BR}*"--!"[^{}\n][^\n]*\n/{B}*"--!" { // multi line comment if (iDocLine==-1) iDocLine=yyLineNr; // signal clk :in std_logic; --!@brief global clock // --!@brief global reset // signal reset:in std_logic; // these two comments are detected as a multi line comment QCString qc(yytext); int len=qc.contains('\n')+yyLineNr-1; if (YY_START!=Comment) // Start of the comment block { bufferClear(); iTextCounter=0; startComment=yyLineNr; g_lastCommentContext=YY_START; } Entry* pTemp=getEntryAtLine(current_root,len); if (pTemp) { // found one line comment, add it to the entry on this line pTemp->briefLine=yyLineNr; pTemp->brief+=yytext; VhdlDocGen::prepareComment(pTemp->brief); } else { addText(yytext,yyleng); } lineCount(); BEGIN(Comment); } ^{B}*"--!"[^\n]* { if (iDocLine==-1) iDocLine=yyLineNr; addText(yytext,yyleng); lineCount(); } .|\n { // found end of comment block QCString qcs; getBufText(qcs,iTextCounter); VhdlDocGen::prepareComment(qcs); handleCommentBlock(qcs,FALSE); bufferClear(); unput(*yytext); BEGIN(g_lastCommentContext); } <*>"--!"[^\n]* { // one line comment if (iDocLine==-1) iDocLine=yyLineNr; QCString qcs(yytext); int j=qcs.find("--!"); qcs=qcs.right(qcs.length()-3-j); //printf("--> handleCommentBlock line %d\n",yyLineNr); Entry* pTemp=getEntryAtLine(current_root,yyLineNr); if (pTemp) { pTemp->briefLine=yyLineNr; pTemp->brief+=qcs; iDocLine=-1; } else { handleCommentBlock(qcs,TRUE); } //printf("--> end: handleCommentBlock line %d\n",yyLineNr); bufferClear(); } <*>{COMMENT} { } <*>\n { lineCount(); addText(yytext,yyleng); // printf("\n new-line [%d]",yyLineNr); BEGIN(Start); } <*>{NAME} { addText(yytext,yyleng); lineCount(); } <*>{B}* { addText(yytext,yyleng); lineCount(); } <*>. { addText(yytext,yyleng); lineCount(); } %% static void initEntry(Entry *e) { e->fileName = yyFileName; initGroupInfo(e); } static void newEntry() { // Add only enties/architectures/packages to root // and signals to classes where they were found // ENTITY dlatch_93 IS -- VHDL'93-Syntax !!! // PORT (d, clk : IN bit; // q, qbar : OUT bit); // GROUP path IS (SIGNAL, SIGNAL); // GROUP d_to_q : path (d, q); // ATTRIBUTE propagation : time; // END dlatch_93; if (current->spec==VhdlDocGen::ENTITY || current->spec==VhdlDocGen::PACKAGE || current->spec==VhdlDocGen::ARCHITECTURE || current->spec==VhdlDocGen::PACKAGE_BODY) { current_root->addSubEntry(current); } else { if (lastCompound) { lastCompound->addSubEntry(current); } else { if (lastEntity) { lastEntity->addSubEntry(current); } else { current_root->addSubEntry(current); // should not happen! } } } previous = current; current = new Entry ; initEntry(current); } static void handleCommentBlock(const QCString &doc,bool brief) { int position=0; bool needsEntry=FALSE; Protection protection=Public; int lineNr = iDocLine; if (brief) current->briefLine = iDocLine; else current->docLine = iDocLine; //printf("parseCommentBlock %p [%s]\n",current,doc.data()); while (parseCommentBlock( g_thisParser, current, doc, // text yyFileName, // file lineNr, // line of block start brief, docBlockAutoBrief, FALSE, protection, position, needsEntry ) ) { //printf("parseCommentBlock position=%d [%s]\n",position,doc.data()+position); if (needsEntry) newEntry(); } if (needsEntry) { newEntry(); } if (docBlockTerm) { unput(docBlockTerm); docBlockTerm=0; } iDocLine=-1; } #if 0 /*! * adds grouping to the entries */ static void mergeGrouping(const Entry* ce,int) { EntryListIterator eli(*ce->children()); Entry *rt; for (;(rt=eli.current());++eli) { if (rt->section==Entry::GROUPDOC_SEC) { if (openGroups) { QCString tt=(QCString)qrl.last(); if (!tt.isEmpty()) { rt->groups->append(new Grouping(tt.data(),Grouping::GROUPING_LOWEST)); } } qrl.append(rt->name); } if ((strcmp(rt->name.data(),"endgroup")==0) && !qrl.isEmpty()) { qrl.remove((QCString)qrl.last()); openGroups--; } if ((strcmp(rt->name.data(),"startgroup")==0)) { openGroups++; } if (rt->section!=Entry::GROUPDOC_SEC && openGroups && !qrl.isEmpty()) { rt->groups->append(new Grouping(qrl.last().data(),Grouping::GROUPING_LOWEST)); } mergeGrouping(rt,openGroups); } } #endif /* * adds the library|use statements to the next class (entity|package|architecture|package body * library ieee * entity xxx * ..... * library * package * enity zzz * ..... * and so on.. */ void mapLibPackage(const Entry* ce) { Entry *lastComp=0; while (TRUE) { bool found = FALSE; Entry *rt=0; //const QList *epp=ce->children(); EntryListIterator eli(*ce->children()); EntryListIterator eli1=eli; for (;(rt=eli.current()),eli1=eli;++eli) { if (rt->spec==VhdlDocGen::LIBRARY || rt->spec==VhdlDocGen::USE) // top level library or use statement { Entry *temp=0; for (;(temp=eli1.current());++eli1) // find next entity { if (temp->spec==VhdlDocGen::ENTITY || temp->spec==VhdlDocGen::PACKAGE || temp->spec==VhdlDocGen::ARCHITECTURE || temp->spec==VhdlDocGen::PACKAGE_BODY) { Entry *ee=new Entry(*rt); //append a copy to entries sublist temp->addSubEntry(ee); found=TRUE; rt->spec=-1; //nullify entry rt->section=0; lastComp=temp; break; } }//for if (lastComp && rt->spec!=-1) { Entry *ee=new Entry(*rt); //append a copy to entries sublist lastComp->addSubEntry(ee); found=TRUE; rt->spec=-1; //nullify entry rt->section=0; } }//if }//for if (!found) // nothing left to do { return; } }//while }//MapLib #if 0 /*! * merges a brief descriptions to the next entry */ void mergeBrief(const Entry* ce) { EntryListIterator eli(*ce->children()); Entry *rt; for (;(rt=eli.current());++eli) { if (found && (!eMerge.brief.isEmpty() || !eMerge.doc.isEmpty())) { rt->doc+=eMerge.doc.data(); rt->docLine=eMerge.docLine; rt->brief+=eMerge.brief.data(); rt->briefLine=eMerge.briefLine; found=FALSE; } if ((strcmp(rt->name.data(),"string")==0)) { eMerge.reset(); eMerge.doc+=rt->doc.data(); eMerge.docLine=rt->docLine; eMerge.brief+=rt->brief.data(); eMerge.briefLine=rt->briefLine; found=TRUE; } MergeBrief(rt); } } #endif void vhdlscanFreeScanner() { #if defined(YY_FLEX_SUBMINOR_VERSION) if (g_lexInit) { vhdlscanYYlex_destroy(); } if (g_buf) { free(g_buf); } g_buf=0; #endif } void VHDLLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root) { inputFile.setName(fileName); //uint jfile=inputFile.size(); ::parserInit(); yyFileName=QCString(fileName); groupEnterFile(fileName,yyLineNr); g_thisParser = this; g_inputFromFile = FALSE; inputPosition = 0; assert(root!=0); inputString=fileBuf; current_root = root; global_root = root; current=new Entry; initEntry(current); //current_root->name=QCString("XXX"); // dummy name for root if (!inputFile.open(IO_ReadOnly)) { err("\n\n could not open file: %s !!\n\n",yyFileName.data()); return ; } if (g_lexInit) { vhdlscanYYrestart(vhdlscanYYin); unput(' '); BEGIN(Start); } vhdlscanYYlex(); g_lexInit=TRUE; free(g_buf); g_buf=0; delete current; current=0; groupLeaveFile(yyFileName,yyLineNr); inputFile.close(); //mergeBrief(current_root); //mergeGrouping(current_root,0); mapLibPackage(current_root); } void VHDLLanguageScanner::parsePrototype(const char *text) { // will be called when a \fn command is found in a comment block QCString ss,ret; bool sem=FALSE; bool func=FALSE; QList qs; qs.setAutoDelete(TRUE); VhdlDocGen::parseFuncProto(text,qs,ss,ret,TRUE); int count=qs.count(); if (stricmp(ret.data(),"function")==0) { func=TRUE; } if (count<1 && !func) { return; } Entry *pp = new Entry; initEntry(pp); pp->name=ss.stripWhiteSpace(); pp->args+='('; for (int j=0;jargs+=','; } Argument *ars=(Argument*)(qs.at(j)); Argument *arg=new Argument; arg->attrib = ars->attrib; arg->name = ars->name; arg->type = ars->type; pp->args+=ars->name.data(); pp->args+=" "; pp->args+=ars->type.data(); pp->argList->append(arg); sem=TRUE; } pp->args+=')'; if (!ret.isEmpty()) pp->spec=VhdlDocGen::FUNCTION; else pp->spec=VhdlDocGen::PROCEDURE; if (pp->section == Entry::MEMBERDOC_SEC && pp->args.isEmpty()) pp->section = Entry::VARIABLEDOC_SEC; pp->type=ret; current_root->addSubEntry(pp); } void VHDLLanguageScanner::parseCode(CodeOutputInterface &codeOutIntf, const char *scopeName, const QCString &input, bool isExampleBlock, const char *exampleName, FileDef *fileDef, int startLine, int endLine, bool inlineFragment, MemberDef *memberDef, bool showLineNumbers ) { ::parseVhdlCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName, fileDef,startLine,endLine,inlineFragment,memberDef, showLineNumbers); }