You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
6.5 KiB
282 lines
6.5 KiB
/* ANTLR Translator Generator
|
|
* Project led by Terence Parr at http://www.jGuru.com
|
|
* Software rights: http://www.antlr.org/license.html
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#include "antlr/config.h"
|
|
|
|
#include <iostream>
|
|
|
|
#include "antlr/AST.h"
|
|
#include "antlr/BaseAST.h"
|
|
|
|
ANTLR_USING_NAMESPACE(std)
|
|
#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
|
|
namespace antlr {
|
|
#endif
|
|
|
|
size_t BaseAST::getNumberOfChildren() const
|
|
{
|
|
RefBaseAST t = this->down;
|
|
size_t n = 0;
|
|
if( t )
|
|
{
|
|
n = 1;
|
|
while( t->right )
|
|
{
|
|
t = t->right;
|
|
n++;
|
|
}
|
|
return n;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
void BaseAST::doWorkForFindAll(
|
|
ANTLR_USE_NAMESPACE(std)vector<RefAST>& v,
|
|
RefAST target,bool partialMatch)
|
|
{
|
|
// Start walking sibling lists, looking for matches.
|
|
for (RefAST sibling=this;
|
|
sibling;
|
|
sibling=sibling->getNextSibling())
|
|
{
|
|
if ( (partialMatch && sibling->equalsTreePartial(target)) ||
|
|
(!partialMatch && sibling->equalsTree(target)) ) {
|
|
v.push_back(sibling);
|
|
}
|
|
// regardless of match or not, check any children for matches
|
|
if ( sibling->getFirstChild() ) {
|
|
RefBaseAST(sibling->getFirstChild())->doWorkForFindAll(v, target, partialMatch);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Is t an exact structural and equals() match of this tree. The
|
|
* 'this' reference is considered the start of a sibling list.
|
|
*/
|
|
bool BaseAST::equalsList(RefAST t) const
|
|
{
|
|
// the empty tree is not a match of any non-null tree.
|
|
if (!t)
|
|
return false;
|
|
|
|
// Otherwise, start walking sibling lists. First mismatch, return false.
|
|
RefAST sibling=this;
|
|
for (;sibling && t;
|
|
sibling=sibling->getNextSibling(), t=t->getNextSibling()) {
|
|
// as a quick optimization, check roots first.
|
|
if (!sibling->equals(t))
|
|
return false;
|
|
// if roots match, do full list match test on children.
|
|
if (sibling->getFirstChild()) {
|
|
if (!sibling->getFirstChild()->equalsList(t->getFirstChild()))
|
|
return false;
|
|
}
|
|
// sibling has no kids, make sure t doesn't either
|
|
else if (t->getFirstChild())
|
|
return false;
|
|
}
|
|
|
|
if (!sibling && !t)
|
|
return true;
|
|
|
|
// one sibling list has more than the other
|
|
return false;
|
|
}
|
|
|
|
/** Is 'sub' a subtree of this list?
|
|
* The siblings of the root are NOT ignored.
|
|
*/
|
|
bool BaseAST::equalsListPartial(RefAST sub) const
|
|
{
|
|
// the empty tree is always a subset of any tree.
|
|
if (!sub)
|
|
return true;
|
|
|
|
// Otherwise, start walking sibling lists. First mismatch, return false.
|
|
RefAST sibling=this;
|
|
for (;sibling && sub;
|
|
sibling=sibling->getNextSibling(), sub=sub->getNextSibling()) {
|
|
// as a quick optimization, check roots first.
|
|
if (!sibling->equals(sub))
|
|
return false;
|
|
// if roots match, do partial list match test on children.
|
|
if (sibling->getFirstChild())
|
|
if (!sibling->getFirstChild()->equalsListPartial(sub->getFirstChild()))
|
|
return false;
|
|
}
|
|
|
|
if (!sibling && sub)
|
|
// nothing left to match in this tree, but subtree has more
|
|
return false;
|
|
|
|
// either both are null or sibling has more, but subtree doesn't
|
|
return true;
|
|
}
|
|
|
|
/** Is tree rooted at 'this' equal to 't'? The siblings
|
|
* of 'this' are ignored.
|
|
*/
|
|
bool BaseAST::equalsTree(RefAST t) const
|
|
{
|
|
// check roots first
|
|
if (!equals(t))
|
|
return false;
|
|
// if roots match, do full list match test on children.
|
|
if (getFirstChild()) {
|
|
if (!getFirstChild()->equalsList(t->getFirstChild()))
|
|
return false;
|
|
}
|
|
// sibling has no kids, make sure t doesn't either
|
|
else if (t->getFirstChild())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/** Is 'sub' a subtree of the tree rooted at 'this'? The siblings
|
|
* of 'this' are ignored.
|
|
*/
|
|
bool BaseAST::equalsTreePartial(RefAST sub) const
|
|
{
|
|
// the empty tree is always a subset of any tree.
|
|
if (!sub)
|
|
return true;
|
|
|
|
// check roots first
|
|
if (!equals(sub))
|
|
return false;
|
|
// if roots match, do full list partial match test on children.
|
|
if (getFirstChild())
|
|
if (!getFirstChild()->equalsListPartial(sub->getFirstChild()))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/** Walk the tree looking for all exact subtree matches. Return
|
|
* an ASTEnumerator that lets the caller walk the list
|
|
* of subtree roots found herein.
|
|
*/
|
|
ANTLR_USE_NAMESPACE(std)vector<RefAST> BaseAST::findAll(RefAST target)
|
|
{
|
|
ANTLR_USE_NAMESPACE(std)vector<RefAST> roots;
|
|
|
|
// the empty tree cannot result in an enumeration
|
|
if (target) {
|
|
doWorkForFindAll(roots,target,false); // find all matches recursively
|
|
}
|
|
|
|
return roots;
|
|
}
|
|
|
|
/** Walk the tree looking for all subtrees. Return
|
|
* an ASTEnumerator that lets the caller walk the list
|
|
* of subtree roots found herein.
|
|
*/
|
|
ANTLR_USE_NAMESPACE(std)vector<RefAST> BaseAST::findAllPartial(RefAST target)
|
|
{
|
|
ANTLR_USE_NAMESPACE(std)vector<RefAST> roots;
|
|
|
|
// the empty tree cannot result in an enumeration
|
|
if (target)
|
|
doWorkForFindAll(roots,target,true); // find all matches recursively
|
|
|
|
return roots;
|
|
}
|
|
|
|
ANTLR_USE_NAMESPACE(std)string BaseAST::toStringList() const
|
|
{
|
|
ANTLR_USE_NAMESPACE(std)string ts="";
|
|
|
|
if (getFirstChild())
|
|
{
|
|
ts+=" ( ";
|
|
ts+=toString();
|
|
ts+=getFirstChild()->toStringList();
|
|
ts+=" )";
|
|
}
|
|
else
|
|
{
|
|
ts+=" ";
|
|
ts+=toString();
|
|
}
|
|
|
|
if (getNextSibling())
|
|
ts+=getNextSibling()->toStringList();
|
|
|
|
return ts;
|
|
}
|
|
|
|
ANTLR_USE_NAMESPACE(std)string BaseAST::toStringTree() const
|
|
{
|
|
ANTLR_USE_NAMESPACE(std)string ts = "";
|
|
|
|
if (getFirstChild())
|
|
{
|
|
ts+=" ( ";
|
|
ts+=toString();
|
|
ts+=getFirstChild()->toStringList();
|
|
ts+=" )";
|
|
}
|
|
else
|
|
{
|
|
ts+=" ";
|
|
ts+=toString();
|
|
}
|
|
return ts;
|
|
}
|
|
|
|
#ifdef ANTLR_SUPPORT_XML
|
|
/* This whole XML output stuff needs a little bit more thought
|
|
* I'd like to store extra XML data in the node. e.g. for custom ast's
|
|
* with for instance symboltable references. This
|
|
* should be more pluggable..
|
|
* @returns boolean value indicating wether a closetag should be produced.
|
|
*/
|
|
bool BaseAST::attributesToStream( ANTLR_USE_NAMESPACE(std)ostream& out ) const
|
|
{
|
|
out << "text=\"" << this->getText()
|
|
<< "\" type=\"" << this->getType() << "\"";
|
|
|
|
return false;
|
|
}
|
|
|
|
void BaseAST::toStream( ANTLR_USE_NAMESPACE(std)ostream& out ) const
|
|
{
|
|
for( RefAST node = this; node != 0; node = node->getNextSibling() )
|
|
{
|
|
out << "<" << this->typeName() << " ";
|
|
|
|
// Write out attributes and if there is extra data...
|
|
bool need_close_tag = node->attributesToStream( out );
|
|
|
|
if( need_close_tag )
|
|
{
|
|
// got children so write them...
|
|
if( node->getFirstChild() != 0 )
|
|
node->getFirstChild()->toStream( out );
|
|
|
|
// and a closing tag..
|
|
out << "</" << node->typeName() << ">" << endl;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// this is nasty, but it makes the code generation easier
|
|
ANTLR_API RefAST nullAST;
|
|
|
|
#if defined(_MSC_VER) && !defined(__ICL) // Microsoft Visual C++
|
|
extern ANTLR_API AST* const nullASTptr = 0;
|
|
#else
|
|
ANTLR_API AST* const nullASTptr = 0;
|
|
#endif
|
|
|
|
#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
|
|
}
|
|
#endif
|