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

# User Rev Content
1 tim 2469 /* 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     */