#include "antlr/CommonAST.hpp"
#include "antlr/ANTLRException.hpp"
#include "antlr/IOException.hpp"
#include "antlr/ASTFactory.hpp"
#include "antlr/ANTLRUtil.hpp"
#include <istream>
using namespace std;
#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
namespace antlr {
#endif
ASTFactory::ASTFactory()
: default_factory_descriptor(ANTLR_USE_NAMESPACE(std)make_pair(CommonAST::TYPE_NAME,&CommonAST::factory))
{
nodeFactories.resize( Token::MIN_USER_TYPE, &default_factory_descriptor );
}
ASTFactory::ASTFactory( const char* factory_node_name, factory_type fact )
: default_factory_descriptor(ANTLR_USE_NAMESPACE(std)make_pair(factory_node_name, fact))
{
nodeFactories.resize( Token::MIN_USER_TYPE, &default_factory_descriptor );
}
ASTFactory::~ASTFactory()
{
factory_descriptor_list::iterator i = nodeFactories.begin();
while( i != nodeFactories.end() )
{
if( *i != &default_factory_descriptor )
delete *i;
i++;
}
}
void ASTFactory::registerFactory( int type, const char* ast_name, factory_type factory )
{
if( type < Token::MIN_USER_TYPE )
throw ANTLRException("Internal parser error invalid type passed to RegisterFactory");
if( factory == 0 )
throw ANTLRException("Internal parser error 0 factory passed to RegisterFactory");
if( nodeFactories.size() < (static_cast<unsigned int>(type)+1) )
nodeFactories.resize( type+1, &default_factory_descriptor );
nodeFactories[type] = new ANTLR_USE_NAMESPACE(std)pair<const char*, factory_type>( ast_name, factory );
}
void ASTFactory::setMaxNodeType( int type )
{
if( nodeFactories.size() < (static_cast<unsigned int>(type)+1) )
nodeFactories.resize( type+1, &default_factory_descriptor );
}
RefAST ASTFactory::create()
{
RefAST node = nodeFactories[0]->second();
node->setType(Token::INVALID_TYPE);
return node;
}
RefAST ASTFactory::create(int type)
{
RefAST t = nodeFactories[type]->second();
t->initialize(type,"");
return t;
}
RefAST ASTFactory::create(int type, const ANTLR_USE_NAMESPACE(std)string& txt)
{
RefAST t = nodeFactories[type]->second();
t->initialize(type,txt);
return t;
}
#ifdef ANTLR_SUPPORT_XML
RefAST ASTFactory::create(const ANTLR_USE_NAMESPACE(std)string& type_name, ANTLR_USE_NAMESPACE(std)istream& infile )
{
factory_descriptor_list::iterator fact = nodeFactories.begin();
while( fact != nodeFactories.end() )
{
if( type_name == (*fact)->first )
{
RefAST t = (*fact)->second();
t->initialize(infile);
return t;
}
fact++;
}
string error = "ASTFactory::create: Unknown AST type '" + type_name + "'";
throw ANTLRException(error);
}
#endif
RefAST ASTFactory::create(RefAST tr)
{
if (!tr)
return nullAST;
RefAST t = nodeFactories[tr->getType()]->second();
t->initialize(tr);
return t;
}
RefAST ASTFactory::create(RefToken tok)
{
RefAST t = nodeFactories[tok->getType()]->second();
t->initialize(tok);
return t;
}
void ASTFactory::addASTChild(ASTPair& currentAST, RefAST child)
{
if (child)
{
if (!currentAST.root)
{
currentAST.root = child;
}
else
{
if (!currentAST.child)
{
currentAST.root->setFirstChild(child);
}
else
{
currentAST.child->setNextSibling(child);
}
}
currentAST.child = child;
currentAST.advanceChildToEnd();
}
}
RefAST ASTFactory::dup(RefAST t)
{
if( t )
return t->clone();
else
return RefAST(nullASTptr);
}
RefAST ASTFactory::dupList(RefAST t)
{
RefAST result = dupTree(t); RefAST nt = result;
while( t )
{ t = t->getNextSibling();
nt->setNextSibling(dupTree(t)); nt = nt->getNextSibling();
}
return result;
}
RefAST ASTFactory::dupTree(RefAST t)
{
RefAST result = dup(t); if( t )
result->setFirstChild( dupList(t->getFirstChild()) );
return result;
}
RefAST ASTFactory::make(ANTLR_USE_NAMESPACE(std)vector<RefAST>& nodes)
{
if ( nodes.size() == 0 )
return RefAST(nullASTptr);
RefAST root = nodes[0];
RefAST tail = RefAST(nullASTptr);
if( root )
root->setFirstChild(RefAST(nullASTptr));
for( unsigned int i = 1; i < nodes.size(); i++ )
{
if ( nodes[i] == 0 ) continue;
if ( root == 0 ) root = tail = nodes[i];
else if ( tail == 0 )
{
root->setFirstChild(nodes[i]);
tail = root->getFirstChild();
}
else
{
tail->setNextSibling(nodes[i]);
tail = tail->getNextSibling();
}
if( tail ) {
while (tail->getNextSibling())
tail = tail->getNextSibling();
}
}
return root;
}
RefAST ASTFactory::make(ASTArray* nodes)
{
RefAST ret = make(nodes->array);
delete nodes;
return ret;
}
void ASTFactory::makeASTRoot( ASTPair& currentAST, RefAST root )
{
if (root)
{
root->addChild(currentAST.root);
currentAST.child = currentAST.root;
currentAST.advanceChildToEnd();
currentAST.root = root;
}
}
void ASTFactory::setASTNodeFactory( const char* factory_node_name,
factory_type factory )
{
default_factory_descriptor.first = factory_node_name;
default_factory_descriptor.second = factory;
}
#ifdef ANTLR_SUPPORT_XML
bool ASTFactory::checkCloseTag( ANTLR_USE_NAMESPACE(std)istream& in )
{
char ch;
if( in.get(ch) )
{
if( ch == '<' )
{
char ch2;
if( in.get(ch2) )
{
if( ch2 == '/' )
{
in.putback(ch2);
in.putback(ch);
return true;
}
in.putback(ch2);
in.putback(ch);
return false;
}
}
in.putback(ch);
return false;
}
return false;
}
void ASTFactory::loadChildren( ANTLR_USE_NAMESPACE(std)istream& infile,
RefAST current )
{
char ch;
for(;;) {
eatwhite(infile);
infile.get(ch); if( ch != '<' )
{
string error = "Invalid XML file... no '<' found (";
error += ch + ")";
throw IOException(error);
}
infile.get(ch);
if( ch == '/' ) {
string temp;
temp = read_identifier( infile );
if( strcmp(temp.c_str(), current->typeName() ) != 0 )
{
string error = "Invalid XML file... close tag does not match start tag: ";
error += current->typeName();
error += " closed by " + temp;
throw IOException(error);
}
infile.get(ch);
if( ch != '>' )
{
string error = "Invalid XML file... no '>' found (";
error += ch + ")";
throw IOException(error);
}
break;
}
infile.putback(ch);
infile.putback('<');
RefAST child = LoadAST(infile);
current->addChild( child );
}
}
void ASTFactory::loadSiblings(ANTLR_USE_NAMESPACE(std)istream& infile,
RefAST current )
{
for(;;)
{
eatwhite(infile);
if( infile.eof() )
break;
if( checkCloseTag(infile) )
break;
RefAST sibling = LoadAST(infile);
current->setNextSibling(sibling);
}
}
RefAST ASTFactory::LoadAST( ANTLR_USE_NAMESPACE(std)istream& infile )
{
RefAST current = nullAST;
char ch;
eatwhite(infile);
if( !infile.get(ch) )
return nullAST;
if( ch != '<' )
{
string error = "Invalid XML file... no '<' found (";
error += ch + ")";
throw IOException(error);
}
string ast_type = read_identifier(infile);
current = create( ast_type, infile );
if( current == nullAST )
{
string error = "Unsuported AST type: " + ast_type;
throw IOException(error);
}
eatwhite(infile);
infile.get(ch);
if( ch == '/' )
{
infile.get(ch); if( ch != '>' )
{
string error = "Invalid XML file... no '>' found after '/' (";
error += ch + ")";
throw IOException(error);
}
loadSiblings( infile, current );
return current;
}
if( ch != '>' )
{
string error = "Invalid XML file... no '>' found (";
error += ch + ")";
throw IOException(error);
}
loadChildren( infile, current );
loadSiblings( infile, current );
return current;
}
#endif // ANTLR_SUPPORT_XML
#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
}
#endif