1 /******************************************************************************
3 * Copyright (C) 2014 by M. Kreis
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.
14 #include <qfileinfo.h>
15 #include <qstringlist.h>
16 #include "vhdljjparser.h"
18 #include "vhdldocgen.h"
24 #include "commentscan.h"
26 #include "definition.h"
27 #include "searchindex.h"
28 #include "outputlist.h"
29 #include "arguments.h"
31 #include "VhdlParserIF.h"
33 using namespace vhdl::parser;
36 static ParserInterface *g_thisParser;
38 static QCString yyFileName;
39 static int yyLineNr = 1;
40 static int* lineParse;
41 static int iDocLine = -1;
42 static QCString inputString;
43 static Entry* gBlock = 0;
44 static Entry* previous = 0;
45 //-------------------------------------------------------
47 static Entry* oldEntry;
48 static bool varr=FALSE;
49 static QCString varName;
51 static QList<Entry> instFiles;
52 static QList<Entry> libUse;
53 static QList<Entry> lineEntry;
55 Entry* VhdlParser::currentCompound=0;
56 Entry* VhdlParser::tempEntry=0;
57 Entry* VhdlParser::lastEntity=0 ;
58 Entry* VhdlParser::lastCompound=0 ;
59 Entry* VhdlParser::current=0;
60 Entry* VhdlParser::current_root = 0;
61 QCString VhdlParser::compSpec;
62 QCString VhdlParser::currName;
63 QCString VhdlParser::confName;
64 QCString VhdlParser::genLabels;
65 QCString VhdlParser::lab;
66 QCString VhdlParser::forL;
68 int VhdlParser::param_sec = 0;
69 int VhdlParser::parse_sec=0;
70 int VhdlParser::currP=0;
71 int VhdlParser::levelCounter;
73 static QList<VhdlConfNode> configL;
83 static bool doxComment=FALSE; // doxygen comment ?
84 static QCString strComment;
87 bool checkMultiComment(QCString& qcs,int line);
88 QList<Entry>* getEntryAtLine(const Entry* ce,int line);
90 //-------------------------------------
92 QList<VhdlConfNode>& getVhdlConfiguration() { return configL; }
93 QList<Entry>& getVhdlInstList() { return instFiles; }
95 Entry* getVhdlCompound()
97 if (VhdlParser::lastEntity) return VhdlParser::lastEntity;
98 if (VhdlParser::lastCompound) return VhdlParser::lastCompound;
102 void startCodeBlock(int index)
104 int ll=strComment.length();
105 if (!gBlock) gBlock = new Entry;
106 iCodeLen=inputString.findRev(strComment.data())+ll;
107 // fprintf(stderr,"\n startin code..%d %d %d\n",iCodeLen,num_chars,ll);
109 int len=strComment.length();
110 QCString name=strComment.right(len-index);//
111 name=VhdlDocGen::getIndexWord(name.data(),1);
113 gBlock->name="misc"+ VhdlDocGen::getRecordNumber();
117 gBlock->startLine=yyLineNr;
118 gBlock->bodyLine=yyLineNr;
120 strComment=strComment.left(index);
121 VhdlDocGen::prepareComment(strComment);
122 gBlock->brief+=strComment;
125 void makeInlineDoc(int endCode)
127 int len=endCode-iCodeLen;
128 if (!gBlock) gBlock = new Entry;
129 QCString par=inputString.mid(iCodeLen,len);
130 //fprintf(stderr,"\n inline code: \n<%s>",par.data());
132 gBlock->inbodyDocs=par;
133 gBlock->section=Entry::VARIABLE_SEC;
134 gBlock->spec=VhdlDocGen::MISCELLANEOUS;
135 gBlock->fileName = yyFileName;
136 gBlock->endBodyLine=yyLineNr-1;
137 gBlock->lang=SrcLangExt_VHDL;
138 Entry *temp=new Entry(*gBlock);
139 Entry* compound=getVhdlCompound();
143 compound->addSubEntry(temp);
147 temp->type="misc"; // global code like library ieee...
148 VhdlParser::current_root->addSubEntry(temp);
150 strComment.resize(0);
155 bool isConstraintFile(const QCString &fileName,const QCString &ext)
157 return fileName.right(ext.length())==ext;
161 void VHDLLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root,
168 // fprintf(stderr,"\n ============= %s\n ==========\n",fileBuf);
170 if (strlen(fileName)==0)
175 yyFileName+=fileName;
177 bool xilinx_ucf=isConstraintFile(yyFileName,".ucf");
178 bool altera_qsf=isConstraintFile(yyFileName,".qsf");
180 // support XILINX(ucf) and ALTERA (qsf) file
184 VhdlDocGen::parseUCF(fileBuf,root,yyFileName,FALSE);
189 VhdlDocGen::parseUCF(fileBuf,root,yyFileName,TRUE);
192 libUse.setAutoDelete(true);
194 VhdlParser::current_root=root;
195 VhdlParser::lastCompound=0;
196 VhdlParser::lastEntity=0;
197 VhdlParser::currentCompound=0;
198 VhdlParser::lastEntity=0;
200 VhdlParser::current=new Entry();
201 VhdlParser::initEntry(VhdlParser::current);
202 groupEnterFile(fileName,yyLineNr);
203 lineParse=new int[200]; // Dimitri: dangerous constant: should be bigger than largest token id in VhdlParserConstants.h
204 VhdlParserIF::parseVhdlfile(fileBuf,inLine);
206 delete VhdlParser::current;
207 VhdlParser::current=0;
210 VhdlParser::mapLibPackage(root);
213 yyFileName.resize(0);
215 VhdlDocGen::resetCodeVhdlParserState();
218 void VhdlParser::lineCount()
223 void VhdlParser::lineCount(const char* text)
225 for (const char* c=text ; *c ; ++c )
227 yyLineNr += (*c == '\n') ;
231 void isVhdlDocPending()
233 if (!str_doc.pending) return;
235 str_doc.pending=FALSE;
236 oldEntry=0; // prevents endless recursion
237 iDocLine=str_doc.iDocLine;
238 VhdlParser::handleCommentBlock(str_doc.doc,str_doc.brief);
242 void VhdlParser::initEntry(Entry *e)
244 e->fileName = yyFileName;
245 e->lang = SrcLangExt_VHDL;
250 void VhdlParser::newEntry()
252 if (current->spec==VhdlDocGen::ENTITY ||
253 current->spec==VhdlDocGen::PACKAGE ||
254 current->spec==VhdlDocGen::ARCHITECTURE ||
255 current->spec==VhdlDocGen::PACKAGE_BODY)
257 current_root->addSubEntry(current);
263 lastCompound->addSubEntry(current);
269 lastEntity->addSubEntry(current);
273 current_root->addSubEntry(current);
278 current = new Entry ;
282 bool checkInlineCode(QCString & doc)
284 int index=doc.find("\\code");
289 startCodeBlock(index);
296 void VhdlParser::handleFlowComment(const char* doc)
300 if (VhdlDocGen::getFlowMember())
303 qcs=qcs.stripWhiteSpace();
304 qcs.stripPrefix("--#");
305 FlowChart::addFlowChart(FlowChart::COMMENT_NO,0,0,qcs.data());
310 void VhdlParser::handleCommentBlock(const char* doc1,bool brief)
316 // fprintf(stderr,"\n %s",doc.data());
317 if (doc.isEmpty()) return;
319 if (checkMultiComment(doc,yyLineNr))
321 strComment.resize(0);
325 isIn=checkInlineCode(doc);
326 bool isEndCode=doc.contains("\\endcode");
330 int end=inputString.find(doc.data(),iCodeLen);
332 strComment.resize(0);
341 VhdlDocGen::prepareComment(doc);
343 bool needsEntry=FALSE;
344 Protection protection=Public;
346 if (oldEntry==current)
348 //printf("\n find pending message < %s > at line: %d \n ",doc.data(),iDocLine);
350 str_doc.iDocLine=iDocLine;
352 str_doc.pending=TRUE;
360 current->briefLine = yyLineNr;
364 current->docLine = yyLineNr;
366 // printf("parseCommentBlock file<%s>\n [%s]\n at line [%d] \n ",yyFileName.data(),doc.data(),iDocLine);
368 int j=doc.find("[plant]");
375 while (parseCommentBlock(
380 iDocLine, // line of block start
390 //printf("parseCommentBlock position=%d [%s]\n",position,doc.data()+position);
391 if (needsEntry) newEntry();
398 current->name=varName;
399 current->section=Entry::VARIABLEDOC_SEC;
405 strComment.resize(0);
408 void VHDLLanguageScanner::parsePrototype(const char *text)
414 void VhdlParser::addCompInst(const char *n, const char* instName, const char* comp,int iLine)
416 current->spec=VhdlDocGen::INSTANTIATION;
417 current->section=Entry::VARIABLE_SEC;
418 current->startLine=iLine;
419 current->bodyLine=iLine;
420 current->type=instName; // foo:instname e.g proto or work. proto(ttt)
421 current->exception=genLabels.lower(); // |arch|label1:label2...
422 current->name=n; // foo
425 current->args=lastCompound->name; // architecture name
427 current->includeName=comp; // component/enity/configuration
428 int u=genLabels.find("|",1);
431 current->write=genLabels.right(genLabels.length()-u);
432 current->read=genLabels.left(u);
434 //printf (" \n genlable: [%s] inst: [%s] name: [%s] %d\n",n,instName,comp,iLine);
438 current->args=lastCompound->name;
439 if (true) // !findInstant(current->type))
442 instFiles.append(new Entry(*current));
445 Entry *temp=current; // hold current pointer (temp=oldEntry)
446 current=new Entry; // (oldEntry != current)
455 void VhdlParser::addVhdlType(const char *n,int startLine,int section,
456 uint64 spec,const char* args,const char* type,Protection prot)
459 if (isFuncProcProced() || VhdlDocGen::getFlowMember()) return;
461 if (parse_sec==GEN_SEC)
463 spec= VhdlDocGen::GENERIC;
466 QStringList ql=QStringList::split(",",name,FALSE);
468 for (uint u=0;u<ql.count();u++)
470 current->name=ql[u].utf8();
471 current->startLine=startLine;
472 current->bodyLine=startLine;
473 current->section=section;
475 current->fileName=yyFileName;
476 if (current->args.isEmpty())
481 current->protection=prot;
483 if (!lastCompound && (section==Entry::VARIABLE_SEC) && (spec == VhdlDocGen::USE || spec == VhdlDocGen::LIBRARY) )
485 libUse.append(new Entry(*current));
492 void VhdlParser::createFunction(const char *imp,uint64 spec,const char *fn)
494 QCString impure(imp);
497 current->section=Entry::FUNCTION_SEC;
499 if (impure=="impure" || impure=="pure")
501 current->exception=impure;
504 if (parse_sec==GEN_SEC)
506 current->spec= VhdlDocGen::GENERIC;
507 current->section=Entry::FUNCTION_SEC;
510 if (currP==VhdlDocGen::PROCEDURE)
512 current->name=impure;
513 current->exception="";
520 if (spec==VhdlDocGen::PROCESS)
523 current->name=impure;
524 VhdlDocGen::deleteAllChars(current->args,' ');
525 if (!fname.isEmpty())
527 QStringList q1=QStringList::split(",",fname);
528 for (uint ii=0;ii<q1.count();ii++)
530 Argument *arg=new Argument;
531 arg->name=q1[ii].utf8();
532 current->argList->append(arg);
540 bool VhdlParser::isFuncProcProced()
542 if (currP==VhdlDocGen::FUNCTION ||
543 currP==VhdlDocGen::PROCEDURE ||
544 currP==VhdlDocGen::PROCESS
552 void VhdlParser::pushLabel( QCString &label,QCString & val)
558 QCString VhdlParser::popLabel(QCString & q)
560 int i=q.findRev("|");
566 void VhdlParser::addConfigureNode(const char* a,const char*b, bool,bool isLeaf,bool inlineConf)
578 if (!configL.isEmpty())
580 VhdlConfNode* vc=configL.getLast();
586 else if (level<levelCounter)
593 else if (level>levelCounter)
605 confName=lastCompound->name;
608 //fprintf(stderr,"\n[%s %d %d]\n",forL.data(),levelCounter,level);
609 co=new VhdlConfNode(a,b,confName.lower().data(),forL.lower().data(),isLeaf);
613 co->isInlineConf=TRUE;
620 void VhdlParser::addProto(const char *s1,const char *s2,const char *s3,
621 const char *s4,const char *s5,const char *s6)
623 (void)s5; // avoid unused warning
625 QStringList ql=QStringList::split(",",name,FALSE);
627 for (uint u=0;u<ql.count();u++)
629 Argument *arg=new Argument;
630 arg->name=ql[u].utf8();
641 if (parse_sec==GEN_SEC && param_sec==0)
646 if (parse_sec==PARAM_SEC)
654 current->argList->append(arg);
662 * adds the library|use statements to the next class (entity|package|architecture|package body
672 void VhdlParser::mapLibPackage( Entry* root)
674 QList<Entry> epp=libUse;
675 EntryListIterator eli(epp);
677 for (;(rt=eli.current());++eli)
679 if (addLibUseClause(rt->name))
682 EntryListIterator eLib(*root->children());
684 for (eLib.toFirst();(current=eLib.current());++eLib)
686 if (VhdlDocGen::isVhdlClass(current))
688 if (current->startLine > rt->startLine)
691 current->addSubEntry(new Entry(*rt));
698 root->addSubEntry(new Entry(*rt));
704 bool VhdlParser::addLibUseClause(const QCString &type)
706 static bool showIEEESTD=Config_getBool(FORCE_LOCAL_INCLUDES);
708 if (showIEEESTD) // all standard packages and libraries will not be shown
710 if (type.lower().stripPrefix("ieee")) return FALSE;
711 if (type.lower().stripPrefix("std")) return FALSE;
716 int VhdlParser::getLine()
721 void VhdlParser::setLineParsed(int tok)
723 lineParse[tok]=yyLineNr;
726 int VhdlParser::getLine(int tok)
728 int val=lineParse[tok];
730 //assert(val>=0 && val<=yyLineNr);
735 void VhdlParser::createFlow()
737 if (!VhdlDocGen::getFlowMember())
743 if (currP==VhdlDocGen::FUNCTION)
746 FlowChart::alignFuncProc(q,tempEntry->argList,true);
749 else if (currP==VhdlDocGen::PROCEDURE)
752 FlowChart::alignFuncProc(q,tempEntry->argList,false);
757 q=":process( "+tempEntry->args;
761 q.prepend(VhdlDocGen::getFlowMember()->name().data());
763 FlowChart::addFlowChart(FlowChart::START_NO,q,0);
765 if (currP==VhdlDocGen::FUNCTION)
769 else if (currP==VhdlDocGen::PROCEDURE)
778 FlowChart::addFlowChart(FlowChart::END_NO,ret,0);
779 // FlowChart::printFlowList();
780 FlowChart::writeFlowChart();
784 void VhdlParser::setMultCommentLine()
789 void VhdlParser::oneLineComment(QCString qcs)
791 bool isEndCode=qcs.contains("\\endcode");
793 int index = qcs.find("\\code");
796 int end = inputString.find(qcs.data(),iCodeLen);
803 startCodeBlock(index);
804 strComment.resize(0);
807 if (!isEndCode && index==-1)
809 int j=qcs.find("--!");
810 qcs=qcs.right(qcs.length()-3-j);
811 if (!checkMultiComment(qcs,iDocLine))
813 handleCommentBlock(qcs,TRUE);
819 bool checkMultiComment(QCString& qcs,int line)
821 QList<Entry> *pTemp=getEntryAtLine(VhdlParser::current_root,line);
823 if (pTemp->isEmpty()) return false;
825 VhdlDocGen::prepareComment(qcs);
826 while (!pTemp->isEmpty())
828 Entry *e=(Entry*)pTemp->getFirst();
832 pTemp->removeFirst();
837 // returns the vhdl parsed types at line xxx
838 QList<Entry>* getEntryAtLine(const Entry* ce,int line)
840 EntryListIterator eli(*ce->children());
842 for (;(rt=eli.current());++eli)
844 if (rt->bodyLine==line)
846 lineEntry.insert(0,rt);
849 getEntryAtLine(rt,line);