OpenMD 3.0
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
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$
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
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
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
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 */
96{
97 RefAST node = nodeFactories[0]->second();
98 node->setType(Token::INVALID_TYPE);
99 return node;
100}
101
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 */
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
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 */
192{
193 if( t )
194 return t->clone();
195 else
196 return RefAST(nullASTptr);
197}
198
199/** Duplicate tree including siblings of root. */
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 */
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 */
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 */
ASTArray is a class that allows ANTLR to generate code that can create and initialize an array in one...
Definition ASTArray.hpp:23
void addASTChild(ASTPair &currentAST, RefAST child)
Add a child to the current AST.
void makeASTRoot(ASTPair &currentAST, RefAST root)
Make an AST the root of current AST.
void setASTNodeFactory(const char *factory_node_name, factory_type factory)
Set a new default AST type.
virtual RefAST create()
Create new empty AST node. The right default type shou.
ASTFactory()
Make new factory. Per default (Ref)CommonAST instances are generated.
RefAST dupTree(RefAST t)
Duplicate a tree, assuming this is a root node of a tree– duplicate that node and what's below; ignor...
void registerFactory(int type, const char *ast_name, factory_type factory)
Register a node factory for the node type type with name ast_name.
RefAST dupList(RefAST t)
Duplicate tree including siblings of root.
RefAST make(std ::vector< RefAST > &nodes)
Make a tree from a list of nodes.
RefAST dup(RefAST t)
Deep copy a single node.
virtual ~ASTFactory()
Destroy factory.
void setMaxNodeType(int type)
Set the maximum node (AST) type this factory may encounter.
virtual RefAST getFirstChild() const =0
Get the first child of this node; null if no children.
virtual RefAST getNextSibling() const =0
Get the next sibling in line after this one.
virtual void initialize(int t, const std ::string &txt)=0
Various initialization routines.
virtual void setType(int type)=0
Set the token type for this node.
virtual void addChild(RefAST c)=0
Add a node to the end of the child list for this node.
virtual void setFirstChild(RefAST c)=0
Set the first child of a node.
virtual RefAST clone(void) const =0
Clone this AST node.
ASTPair: utility class used for manipulating a pair of ASTs representing the current AST root and cur...
Definition ASTPair.hpp:26