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