1 /* ANTLR Translator Generator
2  * Project led by Terence Parr at http://www.jGuru.com
3  * Software rights: http://www.antlr.org/license.html
4  *
5  * $Id$
6  */
7 
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"
13 
14 #include <iostream>
15 #include <istream>
16 
17 using namespace std;
18 
19 #ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
20 namespace antlr {
21 #endif
22 
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).
28  *
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
32  * specified.
33  *
34  * When registering types gaps between different types are filled with entries
35  * for the default factory.
36  */
37 
38 /// Initialize factory
ASTFactory()39 ASTFactory::ASTFactory()
40 : default_factory_descriptor(ANTLR_USE_NAMESPACE(std)make_pair(CommonAST::TYPE_NAME,&CommonAST::factory))
41 {
42 	nodeFactories.resize( Token::MIN_USER_TYPE, &default_factory_descriptor );
43 }
44 
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)
48  */
ASTFactory(const char * factory_node_name,factory_type fact)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))
51 {
52 	nodeFactories.resize( Token::MIN_USER_TYPE, &default_factory_descriptor );
53 }
54 
55 /// Delete ASTFactory
~ASTFactory()56 ASTFactory::~ASTFactory()
57 {
58 	factory_descriptor_list::iterator i = nodeFactories.begin();
59 
60 	while( i != nodeFactories.end() )
61 	{
62 		if( *i != &default_factory_descriptor )
63 			delete *i;
64 		i++;
65 	}
66 }
67 
68 /// Register a factory for a given AST type
registerFactory(int type,const char * ast_name,factory_type factory)69 void ASTFactory::registerFactory( int type, const char* ast_name, factory_type factory )
70 {
71 	// check validity of arguments...
72 	if( type < Token::MIN_USER_TYPE )
73 		throw ANTLRException("Internal parser error invalid type passed to RegisterFactory");
74 	if( factory == 0 )
75 		throw ANTLRException("Internal parser error 0 factory passed to RegisterFactory");
76 
77 	// resize up to and including 'type' and initalize any gaps to default
78 	// factory.
79 	if( nodeFactories.size() < (static_cast<unsigned int>(type)+1) )
80 		nodeFactories.resize( type+1, &default_factory_descriptor );
81 
82 	// And add new thing..
83 	nodeFactories[type] = new ANTLR_USE_NAMESPACE(std)pair<const char*, factory_type>( ast_name, factory );
84 }
85 
setMaxNodeType(int type)86 void ASTFactory::setMaxNodeType( int type )
87 {
88 	if( nodeFactories.size() < (static_cast<unsigned int>(type)+1) )
89 		nodeFactories.resize( type+1, &default_factory_descriptor );
90 }
91 
92 /** Create a new empty AST node; if the user did not specify
93  *  an AST node type, then create a default one: CommonAST.
94  */
create()95 RefAST ASTFactory::create()
96 {
97 	RefAST node = nodeFactories[0]->second();
98 	node->setType(Token::INVALID_TYPE);
99 	return node;
100 }
101 
create(int type)102 RefAST ASTFactory::create(int type)
103 {
104 	RefAST t = nodeFactories[type]->second();
105 	t->initialize(type,"");
106 	return t;
107 }
108 
create(int type,const ANTLR_USE_NAMESPACE (std)string & txt)109 RefAST ASTFactory::create(int type, const ANTLR_USE_NAMESPACE(std)string& txt)
110 {
111 	RefAST t = nodeFactories[type]->second();
112 	t->initialize(type,txt);
113 	return t;
114 }
115 
116 #ifdef ANTLR_SUPPORT_XML
create(const ANTLR_USE_NAMESPACE (std)string & type_name,ANTLR_USE_NAMESPACE (std)istream & infile)117 RefAST ASTFactory::create(const ANTLR_USE_NAMESPACE(std)string& type_name, ANTLR_USE_NAMESPACE(std)istream& infile )
118 {
119 	factory_descriptor_list::iterator fact = nodeFactories.begin();
120 
121 	while( fact != nodeFactories.end() )
122 	{
123 		if( type_name == (*fact)->first )
124 		{
125 			RefAST t = (*fact)->second();
126 			t->initialize(infile);
127 			return t;
128 		}
129 		fact++;
130 	}
131 
132 	string error = "ASTFactory::create: Unknown AST type '" + type_name + "'";
133 	throw ANTLRException(error);
134 }
135 #endif
136 
137 /** Create a new empty AST node; if the user did not specify
138  *  an AST node type, then create a default one: CommonAST.
139  */
create(RefAST tr)140 RefAST ASTFactory::create(RefAST tr)
141 {
142 	if (!tr)
143 		return nullAST;
144 
145 //	cout << "create(tr)" << endl;
146 
147 	RefAST t = nodeFactories[tr->getType()]->second();
148 	t->initialize(tr);
149 	return t;
150 }
151 
create(RefToken tok)152 RefAST ASTFactory::create(RefToken tok)
153 {
154 //	cout << "create( tok="<< tok->getType() << ", " << tok->getText() << ")" << nodeFactories.size() << endl;
155 	RefAST t = nodeFactories[tok->getType()]->second();
156 	t->initialize(tok);
157 	return t;
158 }
159 
160 /** Add a child to the current AST */
addASTChild(ASTPair & currentAST,RefAST child)161 void ASTFactory::addASTChild(ASTPair& currentAST, RefAST child)
162 {
163 	if (child)
164 	{
165 		if (!currentAST.root)
166 		{
167 			// Make new child the current root
168 			currentAST.root = child;
169 		}
170 		else
171 		{
172 			if (!currentAST.child)
173 			{
174 				// Add new child to current root
175 				currentAST.root->setFirstChild(child);
176 			}
177 			else
178 			{
179 				currentAST.child->setNextSibling(child);
180 			}
181 		}
182 		// Make new child the current child
183 		currentAST.child = child;
184 		currentAST.advanceChildToEnd();
185 	}
186 }
187 
188 /** Deep copy a single node. This function the new clone() methods in the AST
189  * interface. Returns nullAST if t is null.
190  */
dup(RefAST t)191 RefAST ASTFactory::dup(RefAST t)
192 {
193 	if( t )
194 		return t->clone();
195 	else
196 		return RefAST(nullASTptr);
197 }
198 
199 /** Duplicate tree including siblings of root. */
dupList(RefAST t)200 RefAST ASTFactory::dupList(RefAST t)
201 {
202 	RefAST result = dupTree(t);         // if t == null, then result==null
203 	RefAST nt = result;
204 
205 	while( t )
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();
210 	}
211 	return result;
212 }
213 
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.
216  */
dupTree(RefAST t)217 RefAST ASTFactory::dupTree(RefAST t)
218 {
219 	RefAST result = dup(t);		// make copy of root
220 	// copy all children of root.
221 	if( t )
222 		result->setFirstChild( dupList(t->getFirstChild()) );
223 	return result;
224 }
225 
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).
231  */
make(ANTLR_USE_NAMESPACE (std)vector<RefAST> & nodes)232 RefAST ASTFactory::make(ANTLR_USE_NAMESPACE(std)vector<RefAST>& nodes)
233 {
234 	if ( nodes.size() == 0 )
235 		return RefAST(nullASTptr);
236 
237 	RefAST root = nodes[0];
238 	RefAST tail = RefAST(nullASTptr);
239 
240 	if( root )
241 		root->setFirstChild(RefAST(nullASTptr));	// don't leave any old pointers set
242 
243 	// link in children;
244 	for( unsigned int i = 1; i < nodes.size(); i++ )
245 	{
246 		if ( nodes[i] == 0 )		// ignore null nodes
247 			continue;
248 
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 )
252 		{
253 			root->setFirstChild(nodes[i]);
254 			tail = root->getFirstChild();
255 		}
256 		else
257 		{
258 			tail->setNextSibling(nodes[i]);
259 			tail = tail->getNextSibling();
260 		}
261 
262 		if( tail )	// RK: I cannot fathom why this missing check didn't bite anyone else...
263 		{
264 			// Chase tail to last sibling
265 			while (tail->getNextSibling())
266 				tail = tail->getNextSibling();
267 		}
268 	}
269 
270 	return root;
271 }
272 
273 /** Make a tree from a list of nodes, where the nodes are contained
274  * in an ASTArray object
275  */
make(ASTArray * nodes)276 RefAST ASTFactory::make(ASTArray* nodes)
277 {
278 	RefAST ret = make(nodes->array);
279 	delete nodes;
280 	return ret;
281 }
282 
283 /// Make an AST the root of current AST
makeASTRoot(ASTPair & currentAST,RefAST root)284 void ASTFactory::makeASTRoot( ASTPair& currentAST, RefAST root )
285 {
286 	if (root)
287 	{
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();
293 		// Set the new root
294 		currentAST.root = root;
295 	}
296 }
297 
setASTNodeFactory(const char * factory_node_name,factory_type factory)298 void ASTFactory::setASTNodeFactory( const char* factory_node_name,
299 											   factory_type factory )
300 {
301 	default_factory_descriptor.first = factory_node_name;
302 	default_factory_descriptor.second = factory;
303 }
304 
305 #ifdef ANTLR_SUPPORT_XML
checkCloseTag(ANTLR_USE_NAMESPACE (std)istream & in)306 bool ASTFactory::checkCloseTag( ANTLR_USE_NAMESPACE(std)istream& in )
307 {
308 	char ch;
309 
310 	if( in.get(ch) )
311 	{
312 		if( ch == '<' )
313 		{
314 			char ch2;
315 			if( in.get(ch2) )
316 			{
317 				if( ch2 == '/' )
318 				{
319 					in.putback(ch2);
320 					in.putback(ch);
321 					return true;
322 				}
323 				in.putback(ch2);
324 				in.putback(ch);
325 				return false;
326 			}
327 		}
328 		in.putback(ch);
329 		return false;
330 	}
331 	return false;
332 }
333 
loadChildren(ANTLR_USE_NAMESPACE (std)istream & infile,RefAST current)334 void ASTFactory::loadChildren( ANTLR_USE_NAMESPACE(std)istream& infile,
335 										 RefAST current )
336 {
337 	char ch;
338 
339 	for(;;)			// for all children of this node....
340 	{
341 		eatwhite(infile);
342 
343 		infile.get(ch);	// '<'
344 		if( ch != '<' )
345 		{
346 			string error = "Invalid XML file... no '<' found (";
347 			error += ch + ")";
348 			throw IOException(error);
349 		}
350 
351 		infile.get(ch);		// / or text....
352 
353 		if( ch == '/' )		// check for close tag...
354 		{
355 			string temp;
356 
357 			// read until '>' and see if it matches the open tag... if not trouble
358 			temp = read_identifier( infile );
359 
360 			if( strcmp(temp.c_str(), current->typeName() ) != 0 )
361 			{
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);
366 			}
367 
368 			infile.get(ch);	// must be a '>'
369 
370 			if( ch != '>' )
371 			{
372 				string error = "Invalid XML file... no '>' found (";
373 				error += ch + ")";
374 				throw IOException(error);
375 			}
376 			// close tag => exit loop
377 			break;
378 		}
379 
380 		// put our 'look ahead' back where it came from
381 		infile.putback(ch);
382 		infile.putback('<');
383 
384 		// and recurse into the tree...
385 		RefAST child = LoadAST(infile);
386 
387 		current->addChild( child );
388 	}
389 }
390 
loadSiblings(ANTLR_USE_NAMESPACE (std)istream & infile,RefAST current)391 void ASTFactory::loadSiblings(ANTLR_USE_NAMESPACE(std)istream& infile,
392 										RefAST current )
393 {
394 	for(;;)
395 	{
396 		eatwhite(infile);
397 
398 		if( infile.eof() )
399 			break;
400 
401 		if( checkCloseTag(infile) )
402 			break;
403 
404 		RefAST sibling = LoadAST(infile);
405 		current->setNextSibling(sibling);
406 	}
407 }
408 
LoadAST(ANTLR_USE_NAMESPACE (std)istream & infile)409 RefAST ASTFactory::LoadAST( ANTLR_USE_NAMESPACE(std)istream& infile )
410 {
411 	RefAST current = nullAST;
412 	char ch;
413 
414 	eatwhite(infile);
415 
416 	if( !infile.get(ch) )
417 		return nullAST;
418 
419 	if( ch != '<' )
420 	{
421 		string error = "Invalid XML file... no '<' found (";
422 		error += ch + ")";
423 		throw IOException(error);
424 	}
425 
426 	string ast_type = read_identifier(infile);
427 
428 	// create the ast of type 'ast_type'
429 	current = create( ast_type, infile );
430 	if( current == nullAST )
431 	{
432 		string error = "Unsuported AST type: " + ast_type;
433 		throw IOException(error);
434 	}
435 
436 	eatwhite(infile);
437 
438 	infile.get(ch);
439 
440 	// now if we have a '/' here it's a single node. If it's a '>' we get
441 	// a tree with children
442 
443 	if( ch == '/' )
444 	{
445 		infile.get(ch);		// get the closing '>'
446 		if( ch != '>' )
447 		{
448 			string error = "Invalid XML file... no '>' found after '/' (";
449 			error += ch + ")";
450 			throw IOException(error);
451 		}
452 
453 		// get the rest on this level
454 		loadSiblings( infile, current );
455 
456 		return current;
457 	}
458 
459 	// and finaly see if we got the close tag...
460 	if( ch != '>' )
461 	{
462 		string error = "Invalid XML file... no '>' found (";
463 		error += ch + ")";
464 		throw IOException(error);
465 	}
466 
467 	// handle the ones below this level..
468 	loadChildren( infile, current );
469 
470 	// load the rest on this level...
471 	loadSiblings( infile, current );
472 
473 	return current;
474 }
475 #endif // ANTLR_SUPPORT_XML
476 
477 #ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
478 }
479 #endif
480 
481 /* Heterogeneous AST/XML-I/O ramblings...
482  *
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.
486  *
487  * Is it maybe better to register all AST types with the ASTFactory class
488  * together with the respective factory methods.
489  *
490  * More and more I get the impression that hetero ast was a kindoff hack
491  * on top of ANTLR's normal AST system.
492  *
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)
498  *
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.
502  *
503  *
504  */
505