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