/ OSX / libsecurity_codesigning / antlr2 / src / ASTFactory.cpp
ASTFactory.cpp
  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  
 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
 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   */
 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
 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
 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  
 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   */
 95  RefAST ASTFactory::create()
 96  {
 97  	RefAST node = nodeFactories[0]->second();
 98  	node->setType(Token::INVALID_TYPE);
 99  	return node;
100  }
101  
102  RefAST ASTFactory::create(int type)
103  {
104  	RefAST t = nodeFactories[type]->second();
105  	t->initialize(type,"");
106  	return t;
107  }
108  
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
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   */
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  
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 */
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   */
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. */
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   */
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   */
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   */
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
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  
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
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  
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  
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  
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   */