Imported Upstream version 1.8.15
[platform/upstream/doxygen.git] / src / vhdljjparser.cpp
1 /******************************************************************************
2  *
3  * Copyright (C) 2014 by M. Kreis
4  *
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.
10  *
11  */
12
13 #include <qcstring.h>
14 #include <qfileinfo.h>
15 #include <qcstringlist.h>
16 #include "vhdljjparser.h"
17 #include "vhdlcode.h"
18 #include "vhdldocgen.h"
19 #include "message.h"
20 #include "config.h"
21 #include "doxygen.h"
22 #include "util.h"
23 #include "language.h"
24 #include "commentscan.h"
25 #include "index.h"
26 #include "definition.h"
27 #include "searchindex.h"
28 #include "outputlist.h"
29 #include "arguments.h"
30 #include "types.h"
31 #include "VhdlParserIF.h"
32
33 using namespace vhdl::parser;
34 using namespace std;
35
36 static ParserInterface *g_thisParser;
37
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 //-------------------------------------------------------
46
47 static Entry* oldEntry;
48 static bool varr=FALSE;
49 static QCString varName;
50
51 static QList<Entry> instFiles;
52 static QList<Entry> libUse;
53 static QList<Entry> lineEntry;
54
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;
67
68 int VhdlParser::param_sec = 0;
69 int VhdlParser::parse_sec=0;
70 int VhdlParser::currP=0;
71 int VhdlParser::levelCounter;
72
73 static QList<VhdlConfNode> configL;
74
75 static struct
76 {
77   QCString doc;
78   bool brief;
79   bool pending;
80   int iDocLine;
81 } str_doc;
82
83 static QCString strComment;
84 static int iCodeLen;
85 static const char *vhdlFileName = 0;
86
87 bool  checkMultiComment(QCString& qcs,int line);
88 QList<Entry>* getEntryAtLine(const Entry* ce,int line);
89
90 //-------------------------------------
91
92 QList<VhdlConfNode>& getVhdlConfiguration() { return  configL; }
93 QList<Entry>& getVhdlInstList() { return  instFiles; }
94
95 Entry* getVhdlCompound()
96 {
97   if (VhdlParser::lastEntity) return VhdlParser::lastEntity;
98   if (VhdlParser::lastCompound) return VhdlParser::lastCompound;
99   return NULL;
100 }
101
102 bool isConstraintFile(const QCString &fileName,const QCString &ext)
103 {
104   return fileName.right(ext.length())==ext;
105 }
106
107
108 void VHDLLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root,
109                           bool ,QStrList&)
110 {
111   g_thisParser=this;
112   bool inLine=false;
113   inputString=fileBuf;
114
115  // fprintf(stderr,"\n ============= %s\n ==========\n",fileBuf);
116
117   if (strlen(fileName)==0)
118   {
119     inLine=true;
120   }
121
122   yyFileName+=fileName;
123
124   bool xilinx_ucf=isConstraintFile(yyFileName,".ucf");
125   bool altera_qsf=isConstraintFile(yyFileName,".qsf");
126
127   // support XILINX(ucf) and ALTERA (qsf) file
128
129   if (xilinx_ucf)
130   {
131     VhdlDocGen::parseUCF(fileBuf,root,yyFileName,FALSE);
132     return;
133   }
134   if (altera_qsf)
135   {
136     VhdlDocGen::parseUCF(fileBuf,root,yyFileName,TRUE);
137     return;
138   }
139   libUse.setAutoDelete(true);
140   yyLineNr=1;
141   VhdlParser::current_root=root;
142   VhdlParser::lastCompound=0;
143   VhdlParser::lastEntity=0;
144   VhdlParser::currentCompound=0;
145   VhdlParser::lastEntity=0;
146   oldEntry = 0;
147   VhdlParser::current=new Entry();
148   VhdlParser::initEntry(VhdlParser::current);
149   groupEnterFile(fileName,yyLineNr);
150   vhdlFileName = fileName;
151   lineParse=new int[200]; // Dimitri: dangerous constant: should be bigger than largest token id in VhdlParserConstants.h
152   VhdlParserIF::parseVhdlfile(fileBuf,inLine);
153
154   delete VhdlParser::current;
155   VhdlParser::current=0;
156
157   if (!inLine)
158   VhdlParser::mapLibPackage(root);
159
160   delete[] lineParse;
161   yyFileName.resize(0);
162   libUse.clear();
163   VhdlDocGen::resetCodeVhdlParserState();
164   vhdlFileName = 0;
165 }
166
167 void VhdlParser::lineCount()
168 {
169   yyLineNr++;
170 }
171
172 void VhdlParser::lineCount(const char* text)
173 {
174   for (const char* c=text ; *c ; ++c )
175   {
176     yyLineNr += (*c == '\n') ;
177   }
178 }
179
180 void isVhdlDocPending()
181 {
182   if (!str_doc.pending) return;
183
184   str_doc.pending=FALSE;
185   oldEntry=0; // prevents endless recursion
186   iDocLine=str_doc.iDocLine;
187   VhdlParser::handleCommentBlock(str_doc.doc,str_doc.brief);
188   iDocLine=-1;
189 }
190
191 void VhdlParser::initEntry(Entry *e)
192 {
193   e->fileName = yyFileName;
194   e->lang     = SrcLangExt_VHDL;
195   isVhdlDocPending();
196   initGroupInfo(e);
197 }
198
199 void VhdlParser::newEntry()
200 {
201   if (current->spec==VhdlDocGen::ENTITY ||
202       current->spec==VhdlDocGen::PACKAGE ||
203       current->spec==VhdlDocGen::ARCHITECTURE ||
204       current->spec==VhdlDocGen::PACKAGE_BODY)
205   {
206     current_root->addSubEntry(current);
207   }
208   else
209   {
210     if (lastCompound)
211     {
212       lastCompound->addSubEntry(current);
213     }
214     else
215     {
216       if (lastEntity)
217       {
218         lastEntity->addSubEntry(current);
219       }
220       else
221       {
222         current_root->addSubEntry(current);
223       }
224     }
225   }
226   previous = current;
227   current = new Entry ;
228   initEntry(current);
229 }
230
231 void VhdlParser::handleFlowComment(const char* doc)
232 {
233         lineCount(doc);
234
235   if (VhdlDocGen::getFlowMember())
236   {
237     QCString qcs(doc);
238     qcs=qcs.stripWhiteSpace();
239     qcs.stripPrefix("--#");
240     FlowChart::addFlowChart(FlowChart::COMMENT_NO,0,0,qcs.data());
241   }
242 }
243
244
245 void VhdlParser::handleCommentBlock(const char* doc1,bool brief)
246 {
247   int position=0;
248   QCString doc;
249   doc.append(doc1);
250  // fprintf(stderr,"\n %s",doc.data());
251   if (doc.isEmpty()) return;
252
253   if (checkMultiComment(doc,yyLineNr))
254   {
255     strComment.resize(0);
256     return;
257   }
258
259   VhdlDocGen::prepareComment(doc);
260
261   bool needsEntry=FALSE;
262   Protection protection=Public;
263
264   if (oldEntry==current)
265   {
266     //printf("\n find pending message  < %s > at line: %d \n ",doc.data(),iDocLine);
267     str_doc.doc=doc;
268     str_doc.iDocLine=iDocLine;
269     str_doc.brief=brief;
270     str_doc.pending=TRUE;
271     return;
272   }
273
274   oldEntry=current;
275
276   if (brief)
277   {
278     current->briefLine = yyLineNr;
279   }
280   else
281   {
282     current->docLine = yyLineNr;
283   }
284   //  printf("parseCommentBlock file<%s>\n [%s]\n at line [%d] \n ",yyFileName.data(),doc.data(),iDocLine);
285
286   int j=doc.find("[plant]");
287   if (j>=0)
288   {
289     doc=doc.remove(j,7);
290     current->stat=true;
291   }
292
293   while (parseCommentBlock(
294         g_thisParser,
295         current,
296         doc,        // text
297         yyFileName, // file
298         iDocLine,   // line of block start
299         brief,
300         0,
301         FALSE,
302         protection,
303         position,
304         needsEntry
305         )
306       )
307   {
308     //printf("parseCommentBlock position=%d [%s]\n",position,doc.data()+position);
309     if (needsEntry) newEntry();
310   }
311   if (needsEntry)
312   {
313     if (varr)
314     {
315       varr=FALSE;
316       current->name=varName;
317       current->section=Entry::VARIABLEDOC_SEC;
318       varName="";
319     }
320     newEntry();
321   }
322   iDocLine=-1;
323   strComment.resize(0);
324 }
325
326 void VHDLLanguageScanner::parsePrototype(const char *text)
327 {
328   varName=text;
329   varr=TRUE;
330 }
331
332 void VhdlParser::addCompInst(const char *n, const char* instName, const char* comp,int iLine)
333 {
334   current->spec=VhdlDocGen::INSTANTIATION;
335   current->section=Entry::VARIABLE_SEC;
336   current->startLine=iLine;
337   current->bodyLine=iLine;
338   current->type=instName;                       // foo:instname e.g proto or work. proto(ttt)
339   current->exception=genLabels.lower();         // |arch|label1:label2...
340   current->name=n;                              // foo
341   if (lastCompound)
342   {
343     current->args=lastCompound->name;             // architecture name
344   }
345   current->includeName=comp;                    // component/enity/configuration
346   int u=genLabels.find("|",1);
347   if (u>0)
348   {
349     current->write=genLabels.right(genLabels.length()-u);
350     current->read=genLabels.left(u);
351   }
352   //printf  (" \n genlable: [%s]  inst: [%s]  name: [%s] %d\n",n,instName,comp,iLine);
353
354   if (lastCompound)
355   {
356     current->args=lastCompound->name;
357     if (true) // !findInstant(current->type))
358     {
359       initEntry(current);
360       instFiles.append(new Entry(*current));
361     }
362
363     Entry *temp=current;  // hold  current pointer  (temp=oldEntry)
364     current=new Entry;     // (oldEntry != current)
365     delete  temp;
366   }
367   else
368   {
369     newEntry();
370   }
371 }
372
373 void VhdlParser::addVhdlType(const char *n,int startLine,int section,
374     uint64 spec,const char* args,const char* type,Protection prot)
375 {
376   QCString name(n);
377   if (isFuncProcProced() || VhdlDocGen::getFlowMember())  return;
378
379   if (parse_sec==GEN_SEC)
380   {
381     spec= VhdlDocGen::GENERIC;
382   }
383
384   QCStringList ql=QCStringList::split(",",name);
385
386   for (uint u=0;u<ql.count();u++)
387   {
388     current->name=ql[u];
389     current->startLine=startLine;
390     current->bodyLine=startLine;
391     current->section=section;
392     current->spec=spec;
393     current->fileName=yyFileName;
394     if (current->args.isEmpty())
395     {
396       current->args=args;
397     }
398     current->type=type;
399     current->protection=prot;
400
401     if (!lastCompound && (section==Entry::VARIABLE_SEC) &&  (spec == VhdlDocGen::USE || spec == VhdlDocGen::LIBRARY) )
402     {
403       libUse.append(new Entry(*current));
404       current->reset();
405     }
406     newEntry();
407   }
408 }
409
410 void VhdlParser::createFunction(const char *imp,uint64 spec,const char *fn)
411 {
412   QCString impure(imp);
413   QCString fname(fn);
414   current->spec=spec;
415   current->section=Entry::FUNCTION_SEC;
416
417   if (impure=="impure" || impure=="pure")
418   {
419     current->exception=impure;
420   }
421
422   if (parse_sec==GEN_SEC)
423   {
424     current->spec= VhdlDocGen::GENERIC;
425     current->section=Entry::FUNCTION_SEC;
426   }
427
428   if (currP==VhdlDocGen::PROCEDURE)
429   {
430     current->name=impure;
431     current->exception="";
432   }
433   else
434   {
435     current->name=fname;
436   }
437
438   if (spec==VhdlDocGen::PROCESS)
439   {
440     current->args=fname;
441     current->name=impure;
442     VhdlDocGen::deleteAllChars(current->args,' ');
443     if (!fname.isEmpty())
444     {
445       QCStringList q1=QCStringList::split(",",fname);
446       for (uint ii=0;ii<q1.count();ii++)
447       {
448         Argument *arg=new Argument;
449         arg->name=q1[ii];
450         current->argList->append(arg);
451       }
452     }
453     return;
454   }
455  }
456
457
458 bool VhdlParser::isFuncProcProced()
459 {
460   if (currP==VhdlDocGen::FUNCTION  ||
461       currP==VhdlDocGen::PROCEDURE ||
462       currP==VhdlDocGen::PROCESS
463      )
464   {
465     return TRUE;
466   }
467   return FALSE;
468 }
469
470 void VhdlParser::pushLabel( QCString &label,QCString & val)
471 {
472   label+="|";
473   label+=val;
474 }
475
476  QCString  VhdlParser::popLabel(QCString & q)
477 {
478   int i=q.findRev("|");
479   if (i<0) return "";
480   q = q.left(i);
481   return q;
482 }
483
484 void VhdlParser::addConfigureNode(const char* a,const char*b, bool,bool isLeaf,bool inlineConf)
485 {
486   VhdlConfNode* co=0;
487   QCString ent;
488   ent=a;
489
490   if (b)
491   {
492     ent=b;
493   }
494   int level=0;
495
496   if (!configL.isEmpty())
497   {
498     VhdlConfNode* vc=configL.getLast();
499     level=vc->level;
500     if (levelCounter==0)
501     {
502       pushLabel(forL,ent);
503     }
504     else if (level<levelCounter)
505     {
506       if (!isLeaf)
507       {
508         pushLabel(forL,ent);
509       }
510     }
511     else if (level>levelCounter)
512     {
513       forL=popLabel(forL);
514     }
515   }
516   else
517   {
518     pushLabel(forL,ent);
519   }
520
521   if (inlineConf)
522   {
523     confName=lastCompound->name;
524   }
525
526   //fprintf(stderr,"\n[%s %d %d]\n",forL.data(),levelCounter,level);
527   co=new VhdlConfNode(a,b,confName.lower().data(),forL.lower().data(),isLeaf);
528
529   if (inlineConf)
530   {
531     co->isInlineConf=TRUE;
532   }
533
534   configL.append(co);
535 }
536
537
538 void VhdlParser::addProto(const char *s1,const char *s2,const char *s3,
539     const char *s4,const char *s5,const char *s6)
540 {
541   (void)s5; // avoid unused warning
542   QCString name=s2;
543   QCStringList ql=QCStringList::split(",",name);
544
545   for (uint u=0;u<ql.count();u++)
546   {
547     Argument *arg=new Argument;
548     arg->name=ql[u];
549     if (s3)
550     {
551       arg->type=s3;
552     }
553     arg->type+=" ";
554     arg->type+=s4;
555     if (s6)
556     {
557       arg->type+=s6;
558     }
559     if (parse_sec==GEN_SEC && param_sec==0)
560     {
561       arg->defval="gen!";
562     }
563
564     if (parse_sec==PARAM_SEC)
565     {
566     //  assert(false);
567     }
568
569     arg->defval+=s1;
570     arg->attrib="";//s6;
571
572     current->argList->append(arg);
573     current->args+=s2;
574     current->args+=",";
575   }
576 }
577
578
579 /*
580  * adds the library|use statements to the next class (entity|package|architecture|package body
581  * library ieee
582  * entity xxx
583  * .....
584  * library
585  * package
586  * enity zzz
587  * .....
588  * and so on..
589  */
590 void VhdlParser::mapLibPackage( Entry* root)
591 {
592   QList<Entry> epp=libUse;
593   EntryListIterator eli(epp);
594   Entry *rt;
595   for (;(rt=eli.current());++eli)
596   {
597     if (addLibUseClause(rt->name))
598     {
599       Entry *current;
600       EntryListIterator eLib(*root->children());
601       bool bFound=FALSE;
602       for (eLib.toFirst();(current=eLib.current());++eLib)
603       {
604         if (VhdlDocGen::isVhdlClass(current))
605         {
606           if (current->startLine > rt->startLine)
607           {
608             bFound=TRUE;
609             current->addSubEntry(new Entry(*rt));
610             break;
611           }
612         }
613       }//for
614       if (!bFound)
615       {
616         root->addSubEntry(new Entry(*rt));
617       }
618     } //if
619   }// for
620 }//MapLib
621
622 bool VhdlParser::addLibUseClause(const QCString &type)
623 {
624   static bool showIEEESTD=Config_getBool(FORCE_LOCAL_INCLUDES);
625
626   if (showIEEESTD) // all standard packages and libraries will not be shown
627   {
628     if (type.lower().stripPrefix("ieee")) return FALSE;
629     if (type.lower().stripPrefix("std")) return FALSE;
630   }
631   return TRUE;
632 }
633
634 int VhdlParser::getLine()
635 {
636   return yyLineNr;
637 }
638
639 void VhdlParser::setLineParsed(int tok)
640 {
641   lineParse[tok]=yyLineNr;
642 }
643
644 int VhdlParser::getLine(int tok)
645 {
646   int val=lineParse[tok];
647   if (val<0) val=0;
648   //assert(val>=0 && val<=yyLineNr);
649   return val;
650 }
651
652
653 void VhdlParser::createFlow()
654 {
655   if (!VhdlDocGen::getFlowMember())
656   {
657     return;
658   }
659   QCString q,ret;
660
661   if (currP==VhdlDocGen::FUNCTION)
662   {
663     q=":function( ";
664     FlowChart::alignFuncProc(q,tempEntry->argList,true);
665     q+=")";
666   }
667   else if (currP==VhdlDocGen::PROCEDURE)
668   {
669     q=":procedure (";
670     FlowChart::alignFuncProc(q,tempEntry->argList,false);
671     q+=")";
672   }
673   else
674   {
675     q=":process( "+tempEntry->args;
676     q+=")";
677   }
678
679   q.prepend(VhdlDocGen::getFlowMember()->name().data());
680
681   FlowChart::addFlowChart(FlowChart::START_NO,q,0);
682
683   if (currP==VhdlDocGen::FUNCTION)
684   {
685     ret="end function ";
686   }
687   else if (currP==VhdlDocGen::PROCEDURE)
688   {
689     ret="end procedure";
690   }
691   else
692   {
693     ret="end process ";
694   }
695
696   FlowChart::addFlowChart(FlowChart::END_NO,ret,0);
697   //  FlowChart::printFlowList();
698   FlowChart::writeFlowChart();
699   currP=0;
700 }
701
702 void VhdlParser::setMultCommentLine()
703 {
704   iDocLine=yyLineNr;
705 }
706
707 void VhdlParser::oneLineComment(QCString qcs)
708 {
709     int j=qcs.find("--!");
710     qcs=qcs.right(qcs.length()-3-j);
711     if (!checkMultiComment(qcs,iDocLine))
712     {
713       handleCommentBlock(qcs,TRUE);
714     }
715 }
716
717
718 bool  checkMultiComment(QCString& qcs,int line)
719 {
720   QList<Entry> *pTemp=getEntryAtLine(VhdlParser::current_root,line);
721
722   if (pTemp->isEmpty()) return false;
723
724   VhdlDocGen::prepareComment(qcs);
725   while (!pTemp->isEmpty())
726   {
727     Entry *e=(Entry*)pTemp->getFirst();
728     e->briefLine=line;
729     e->brief+=qcs;
730
731     pTemp->removeFirst();
732   }
733   return true;
734 }
735
736 // returns the vhdl parsed types at line xxx
737 QList<Entry>* getEntryAtLine(const Entry* ce,int line)
738 {
739   EntryListIterator eli(*ce->children());
740   Entry *rt;
741   for (;(rt=eli.current());++eli)
742   {
743     if (rt->bodyLine==line)
744     {
745       lineEntry.insert(0,rt);
746     }
747
748     getEntryAtLine(rt,line);
749   }
750   return &lineEntry;
751 }
752
753 const char *getVhdlFileName(void)
754 {
755   return vhdlFileName;
756 }