|
|
#include "vhdl_file.h"
|
|
|
#include <QDebug>
|
|
|
|
|
|
VHDL_Tools::VHDL_File::VHDL_File()
|
|
|
{
|
|
|
this->scanner = NULL;
|
|
|
}
|
|
|
|
|
|
#define walkForward( node , code ) \
|
|
|
if((node)->childs.count())\
|
|
|
{\
|
|
|
(node) = (node)->childs.first();\
|
|
|
}\
|
|
|
else\
|
|
|
{\
|
|
|
return (code);\
|
|
|
}\
|
|
|
|
|
|
|
|
|
#define skipTokens(node,TokenType) while ((node)->type==(TokenType)){walkForward((node),-1);}
|
|
|
|
|
|
bool VHDL_Tools::VHDL_File::parseFile(const QString &file, bool trashPreviousTree)
|
|
|
{
|
|
|
std::ifstream in_file( file.toStdString().c_str() );
|
|
|
if( ! in_file.good() ) return false;
|
|
|
// if(scanner)
|
|
|
// delete(scanner);
|
|
|
// try
|
|
|
// {
|
|
|
// scanner = new VHDL_Tools::vhdl_Scanner( &in_file ,file);
|
|
|
// }
|
|
|
// catch( std::bad_alloc &ba )
|
|
|
// {
|
|
|
// std::cerr << "Failed to allocate scanner: (" <<
|
|
|
// ba.what() << ")\n";
|
|
|
// return false;
|
|
|
// }
|
|
|
if(scanner==NULL)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
scanner = new VHDL_Tools::vhdl_Scanner( &in_file ,file);
|
|
|
}
|
|
|
catch( std::bad_alloc &ba )
|
|
|
{
|
|
|
std::cerr << "Failed to allocate scanner: (" <<
|
|
|
ba.what() << ")\n";
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
scanner->newFile(&in_file,file,trashPreviousTree);
|
|
|
while (scanner->scan()!=0);
|
|
|
makeParseTree(scanner->getScanTree());
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
VHDL_Tools::VHDL_AST_Node *VHDL_Tools::VHDL_File::getParseTree()
|
|
|
{
|
|
|
return rootNode;
|
|
|
}
|
|
|
|
|
|
int VHDL_Tools::VHDL_File::makeParseTree(VHDL_AST_Node *rootNode)
|
|
|
{
|
|
|
this->rootNode = rootNode;
|
|
|
VHDL_AST_Node *currentNode=rootNode;
|
|
|
QStack<VHDL_AST_Node*> openBlocks;
|
|
|
openBlocks.push(rootNode);
|
|
|
while (currentNode)
|
|
|
{
|
|
|
switch (currentNode->type)
|
|
|
{
|
|
|
case block:
|
|
|
openBlocks.push(currentNode);
|
|
|
walkForward(currentNode,-1);
|
|
|
break;
|
|
|
case entity:
|
|
|
//Declaration or instanciation?
|
|
|
if(!((currentNode->parent->type == colon) && (currentNode->parent->parent->type==identifier)))
|
|
|
{
|
|
|
openBlocks.push(currentNode);
|
|
|
}
|
|
|
walkForward(currentNode,-1);
|
|
|
break;
|
|
|
case units:
|
|
|
if(openBlocks.top()->type==clause)
|
|
|
{
|
|
|
openBlocks.top()->type=units;
|
|
|
walkForward(currentNode,-1);
|
|
|
}
|
|
|
break;
|
|
|
case port:
|
|
|
currentNode->type = static_cast<VHDL_AST_Node_type>(currentNode->type | closedBySemicolon);
|
|
|
openBlocks.push(currentNode);
|
|
|
break;
|
|
|
case generic:
|
|
|
if(!(currentNode->childs.first()->type==map))
|
|
|
{
|
|
|
currentNode->type = static_cast<VHDL_AST_Node_type>(currentNode->type | closedBySemicolon);
|
|
|
openBlocks.push(currentNode);
|
|
|
}
|
|
|
walkForward(currentNode,-1);
|
|
|
break;
|
|
|
case clause:
|
|
|
openBlocks.push(currentNode);
|
|
|
walkForward(currentNode,-1);
|
|
|
break;
|
|
|
case endKw:
|
|
|
closeAndMatchBlock(¤tNode,&openBlocks,QList<VHDL_AST_Node_type>()<<units<<block<<identifier,true);
|
|
|
break;
|
|
|
case leftParen:
|
|
|
openBlocks.push(currentNode);
|
|
|
walkForward(currentNode,-1);
|
|
|
break;
|
|
|
case rightParen:
|
|
|
if((openBlocks.top()->parent->type==port)||(openBlocks.top()->parent->type==generic))
|
|
|
closeAndMatchBlock(¤tNode,&openBlocks,QList<VHDL_AST_Node_type>(),false);
|
|
|
else
|
|
|
closeAndMatchBlock(¤tNode,&openBlocks,QList<VHDL_AST_Node_type>(),false);
|
|
|
break;
|
|
|
case semicolon:
|
|
|
if(IS_CLOSED_BY_SEMICOLON(openBlocks.top()->type))
|
|
|
{
|
|
|
closeAndMatchBlock(¤tNode,&openBlocks,QList<VHDL_AST_Node_type>(),false);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
walkForward(currentNode,0);
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
walkForward(currentNode,0);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int VHDL_Tools::VHDL_File::closeAndMatchBlock(VHDL_Tools::VHDL_AST_Node **currentNode, QStack<VHDL_Tools::VHDL_AST_Node *> *openBlocksContext, QList<VHDL_Tools::VHDL_AST_Node_type> skipTypes, bool endWithSemicolon)
|
|
|
{
|
|
|
VHDL_AST_Node* startNode = openBlocksContext->pop();
|
|
|
|
|
|
if( IS_CLOSED_BY(startNode->type,(*currentNode)->type))
|
|
|
{
|
|
|
walkForward((*currentNode),-1);
|
|
|
for(int i=0;i<skipTypes.length();i++)
|
|
|
{
|
|
|
skipTokens((*currentNode),skipTypes.at(i));
|
|
|
}
|
|
|
if(endWithSemicolon && ((*currentNode)->type==semicolon))
|
|
|
{
|
|
|
walkForward((*currentNode),-1);
|
|
|
(*currentNode)->move(startNode->parent);
|
|
|
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
(*currentNode)->move(startNode->parent);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// TODO improve message !
|
|
|
qDebug() << "Got unexpected close token! @ line:" << (*currentNode)->line << " column:"<< (*currentNode)->column;
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|