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: //depot/code/org.antlr/release/antlr-2.7.7/lib/cpp/src/ASTFactory.cpp#2 $
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
17using namespace std;
18
19#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
20namespace 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
39ASTFactory::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 */
49ASTFactory::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
56ASTFactory::~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
69void 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
86void 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 */
95RefAST ASTFactory::create()
96{
97	RefAST node = nodeFactories[0]->second();
98	node->setType(Token::INVALID_TYPE);
99	return node;
100}
101
102RefAST ASTFactory::create(int type)
103{
104	RefAST t = nodeFactories[type]->second();
105	t->initialize(type,"");
106	return t;
107}
108
109RefAST 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
117RefAST 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 */
140RefAST 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
152RefAST 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 */
161void 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 */
191RefAST 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. */
200RefAST 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 */
217RefAST 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 */
232RefAST 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 */
276RefAST 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
284void 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
298void 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
306bool 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
334void 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
391void 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
409RefAST 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