1 /* ANTLR Translator Generator
2 * Project led by Terence Parr at http://www.jGuru.com
3 * Software rights: http://www.antlr.org/license.html
5 * $Id: //depot/code/org.antlr/release/antlr-2.7.7/lib/cpp/src/ASTFactory.cpp#2 $
8 #include "antlr/CommonAST.hpp"
9 #include "antlr/ANTLRException.hpp"
10 #include "antlr/IOException.hpp"
11 #include "antlr/ASTFactory.hpp"
12 #include "antlr/ANTLRUtil.hpp"
19 #ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
23 /** AST Support code shared by TreeParser and Parser.
24 * We use delegation to share code (and have only one
25 * bit of code to maintain) rather than subclassing
26 * or superclassing (forces AST support code to be
27 * loaded even when you don't want to do AST stuff).
29 * This class collects all factories of AST types used inside the code.
30 * New AST node types are registered with the registerFactory method.
31 * On creation of an ASTFactory object a default AST node factory may be
34 * When registering types gaps between different types are filled with entries
35 * for the default factory.
38 /// Initialize factory
39 ASTFactory::ASTFactory()
40 : default_factory_descriptor(ANTLR_USE_NAMESPACE(std
)make_pair(CommonAST::TYPE_NAME
,&CommonAST::factory
))
42 nodeFactories
.resize( Token::MIN_USER_TYPE
, &default_factory_descriptor
);
45 /** Initialize factory with a non default node type.
46 * factory_node_name should be the name of the AST node type the factory
47 * generates. (should exist during the existance of this ASTFactory instance)
49 ASTFactory::ASTFactory( const char* factory_node_name
, factory_type fact
)
50 : default_factory_descriptor(ANTLR_USE_NAMESPACE(std
)make_pair(factory_node_name
, fact
))
52 nodeFactories
.resize( Token::MIN_USER_TYPE
, &default_factory_descriptor
);
56 ASTFactory::~ASTFactory()
58 factory_descriptor_list::iterator i
= nodeFactories
.begin();
60 while( i
!= nodeFactories
.end() )
62 if( *i
!= &default_factory_descriptor
)
68 /// Register a factory for a given AST type
69 void ASTFactory::registerFactory( int type
, const char* ast_name
, factory_type factory
)
71 // check validity of arguments...
72 if( type
< Token::MIN_USER_TYPE
)
73 throw ANTLRException("Internal parser error invalid type passed to RegisterFactory");
75 throw ANTLRException("Internal parser error 0 factory passed to RegisterFactory");
77 // resize up to and including 'type' and initalize any gaps to default
79 if( nodeFactories
.size() < (static_cast<unsigned int>(type
)+1) )
80 nodeFactories
.resize( type
+1, &default_factory_descriptor
);
82 // And add new thing..
83 nodeFactories
[type
] = new ANTLR_USE_NAMESPACE(std
)pair
<const char*, factory_type
>( ast_name
, factory
);
86 void ASTFactory::setMaxNodeType( int type
)
88 if( nodeFactories
.size() < (static_cast<unsigned int>(type
)+1) )
89 nodeFactories
.resize( type
+1, &default_factory_descriptor
);
92 /** Create a new empty AST node; if the user did not specify
93 * an AST node type, then create a default one: CommonAST.
95 RefAST
ASTFactory::create()
97 RefAST node
= nodeFactories
[0]->second();
98 node
->setType(Token::INVALID_TYPE
);
102 RefAST
ASTFactory::create(int type
)
104 RefAST t
= nodeFactories
[type
]->second();
105 t
->initialize(type
,"");
109 RefAST
ASTFactory::create(int type
, const ANTLR_USE_NAMESPACE(std
)string
& txt
)
111 RefAST t
= nodeFactories
[type
]->second();
112 t
->initialize(type
,txt
);
116 #ifdef ANTLR_SUPPORT_XML
117 RefAST
ASTFactory::create(const ANTLR_USE_NAMESPACE(std
)string
& type_name
, ANTLR_USE_NAMESPACE(std
)istream
& infile
)
119 factory_descriptor_list::iterator fact
= nodeFactories
.begin();
121 while( fact
!= nodeFactories
.end() )
123 if( type_name
== (*fact
)->first
)
125 RefAST t
= (*fact
)->second();
126 t
->initialize(infile
);
132 string error
= "ASTFactory::create: Unknown AST type '" + type_name
+ "'";
133 throw ANTLRException(error
);
137 /** Create a new empty AST node; if the user did not specify
138 * an AST node type, then create a default one: CommonAST.
140 RefAST
ASTFactory::create(RefAST tr
)
145 // cout << "create(tr)" << endl;
147 RefAST t
= nodeFactories
[tr
->getType()]->second();
152 RefAST
ASTFactory::create(RefToken tok
)
154 // cout << "create( tok="<< tok->getType() << ", " << tok->getText() << ")" << nodeFactories.size() << endl;
155 RefAST t
= nodeFactories
[tok
->getType()]->second();
160 /** Add a child to the current AST */
161 void ASTFactory::addASTChild(ASTPair
& currentAST
, RefAST child
)
165 if (!currentAST
.root
)
167 // Make new child the current root
168 currentAST
.root
= child
;
172 if (!currentAST
.child
)
174 // Add new child to current root
175 currentAST
.root
->setFirstChild(child
);
179 currentAST
.child
->setNextSibling(child
);
182 // Make new child the current child
183 currentAST
.child
= child
;
184 currentAST
.advanceChildToEnd();
188 /** Deep copy a single node. This function the new clone() methods in the AST
189 * interface. Returns nullAST if t is null.
191 RefAST
ASTFactory::dup(RefAST t
)
196 return RefAST(nullASTptr
);
199 /** Duplicate tree including siblings of root. */
200 RefAST
ASTFactory::dupList(RefAST t
)
202 RefAST result
= dupTree(t
); // if t == null, then result==null
206 { // for each sibling of the root
207 t
= t
->getNextSibling();
208 nt
->setNextSibling(dupTree(t
)); // dup each subtree, building new tree
209 nt
= nt
->getNextSibling();
214 /** Duplicate a tree, assuming this is a root node of a tree
215 * duplicate that node and what's below; ignore siblings of root node.
217 RefAST
ASTFactory::dupTree(RefAST t
)
219 RefAST result
= dup(t
); // make copy of root
220 // copy all children of root.
222 result
->setFirstChild( dupList(t
->getFirstChild()) );
226 /** Make a tree from a list of nodes. The first element in the
227 * array is the root. If the root is null, then the tree is
228 * a simple list not a tree. Handles null children nodes correctly.
229 * For example, make(a, b, null, c) yields tree (a b c). make(null,a,b)
230 * yields tree (nil a b).
232 RefAST
ASTFactory::make(ANTLR_USE_NAMESPACE(std
)vector
<RefAST
>& nodes
)
234 if ( nodes
.size() == 0 )
235 return RefAST(nullASTptr
);
237 RefAST root
= nodes
[0];
238 RefAST tail
= RefAST(nullASTptr
);
241 root
->setFirstChild(RefAST(nullASTptr
)); // don't leave any old pointers set
244 for( unsigned int i
= 1; i
< nodes
.size(); i
++ )
246 if ( nodes
[i
] == 0 ) // ignore null nodes
249 if ( root
== 0 ) // Set the root and set it up for a flat list
250 root
= tail
= nodes
[i
];
251 else if ( tail
== 0 )
253 root
->setFirstChild(nodes
[i
]);
254 tail
= root
->getFirstChild();
258 tail
->setNextSibling(nodes
[i
]);
259 tail
= tail
->getNextSibling();
262 if( tail
) // RK: I cannot fathom why this missing check didn't bite anyone else...
264 // Chase tail to last sibling
265 while (tail
->getNextSibling())
266 tail
= tail
->getNextSibling();
273 /** Make a tree from a list of nodes, where the nodes are contained
274 * in an ASTArray object
276 RefAST
ASTFactory::make(ASTArray
* nodes
)
278 RefAST ret
= make(nodes
->array
);
283 /// Make an AST the root of current AST
284 void ASTFactory::makeASTRoot( ASTPair
& currentAST
, RefAST root
)
288 // Add the current root as a child of new root
289 root
->addChild(currentAST
.root
);
290 // The new current child is the last sibling of the old root
291 currentAST
.child
= currentAST
.root
;
292 currentAST
.advanceChildToEnd();
294 currentAST
.root
= root
;
298 void ASTFactory::setASTNodeFactory( const char* factory_node_name
,
299 factory_type factory
)
301 default_factory_descriptor
.first
= factory_node_name
;
302 default_factory_descriptor
.second
= factory
;
305 #ifdef ANTLR_SUPPORT_XML
306 bool ASTFactory::checkCloseTag( ANTLR_USE_NAMESPACE(std
)istream
& in
)
334 void ASTFactory::loadChildren( ANTLR_USE_NAMESPACE(std
)istream
& infile
,
339 for(;;) // for all children of this node....
343 infile
.get(ch
); // '<'
346 string error
= "Invalid XML file... no '<' found (";
348 throw IOException(error
);
351 infile
.get(ch
); // / or text....
353 if( ch
== '/' ) // check for close tag...
357 // read until '>' and see if it matches the open tag... if not trouble
358 temp
= read_identifier( infile
);
360 if( strcmp(temp
.c_str(), current
->typeName() ) != 0 )
362 string error
= "Invalid XML file... close tag does not match start tag: ";
363 error
+= current
->typeName();
364 error
+= " closed by " + temp
;
365 throw IOException(error
);
368 infile
.get(ch
); // must be a '>'
372 string error
= "Invalid XML file... no '>' found (";
374 throw IOException(error
);
376 // close tag => exit loop
380 // put our 'look ahead' back where it came from
384 // and recurse into the tree...
385 RefAST child
= LoadAST(infile
);
387 current
->addChild( child
);
391 void ASTFactory::loadSiblings(ANTLR_USE_NAMESPACE(std
)istream
& infile
,
401 if( checkCloseTag(infile
) )
404 RefAST sibling
= LoadAST(infile
);
405 current
->setNextSibling(sibling
);
409 RefAST
ASTFactory::LoadAST( ANTLR_USE_NAMESPACE(std
)istream
& infile
)
411 RefAST current
= nullAST
;
416 if( !infile
.get(ch
) )
421 string error
= "Invalid XML file... no '<' found (";
423 throw IOException(error
);
426 string ast_type
= read_identifier(infile
);
428 // create the ast of type 'ast_type'
429 current
= create( ast_type
, infile
);
430 if( current
== nullAST
)
432 string error
= "Unsuported AST type: " + ast_type
;
433 throw IOException(error
);
440 // now if we have a '/' here it's a single node. If it's a '>' we get
441 // a tree with children
445 infile
.get(ch
); // get the closing '>'
448 string error
= "Invalid XML file... no '>' found after '/' (";
450 throw IOException(error
);
453 // get the rest on this level
454 loadSiblings( infile
, current
);
459 // and finaly see if we got the close tag...
462 string error
= "Invalid XML file... no '>' found (";
464 throw IOException(error
);
467 // handle the ones below this level..
468 loadChildren( infile
, current
);
470 // load the rest on this level...
471 loadSiblings( infile
, current
);
475 #endif // ANTLR_SUPPORT_XML
477 #ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
481 /* Heterogeneous AST/XML-I/O ramblings...
483 * So there is some heterogeneous AST support....
484 * basically in the code generators a new custom ast is generated without
485 * going throug the factory. It also expects the RefXAST to be defined.
487 * Is it maybe better to register all AST types with the ASTFactory class
488 * together with the respective factory methods.
490 * More and more I get the impression that hetero ast was a kindoff hack
491 * on top of ANTLR's normal AST system.
493 * The heteroast stuff will generate trouble for all astFactory.create( ... )
494 * invocations. Most of this is handled via getASTCreateString methods in the
495 * codegenerator. At the moment getASTCreateString(GrammarAtom, String) has
496 * slightly to little info to do it's job (ok the hack that is in now
497 * works, but it's an ugly hack)
499 * An extra caveat is the 'nice' action.g thing. Which also judiciously calls
500 * getASTCreateString methods because it handles the #( ... ) syntax.
501 * And converts that to ASTFactory calls.