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