ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-3.0/src/antlr/ASTFactory.cpp
Revision: 2469
Committed: Fri Dec 2 15:38:03 2005 UTC (18 years, 7 months ago) by tim
File size: 12334 byte(s)
Log Message:
End of the Link --> List
Return of the Oject-Oriented
replace yacc/lex parser with antlr parser

File Contents

# Content
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: ASTFactory.cpp,v 1.1 2005-12-02 15:38:02 tim Exp $
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 */