summaryrefslogtreecommitdiffstats
path: root/lib/antlr/src/ASTFactory.cpp
blob: 98ce6b7a1750584f7b683c3caf8c6d1f72cf4606 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
/* ANTLR Translator Generator
 * Project led by Terence Parr at http://www.jGuru.com
 * Software rights: http://www.antlr.org/license.html
 *
 * $Id$
 */

#include "antlr/CommonAST.hpp"
#include "antlr/ANTLRException.hpp"
#include "antlr/IOException.hpp"
#include "antlr/ASTFactory.hpp"
#include "antlr/ANTLRUtil.hpp"

#include <iostream>
#include <istream>

using namespace std;

#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
namespace antlr {
#endif

/** AST Support code shared by TreeParser and Parser.
 * We use delegation to share code (and have only one
 * bit of code to maintain) rather than subclassing
 * or superclassing (forces AST support code to be
 * loaded even when you don't want to do AST stuff).
 *
 * This class collects all factories of AST types used inside the code.
 * New AST node types are registered with the registerFactory method.
 * On creation of an ASTFactory object a default AST node factory may be
 * specified.
 *
 * When registering types gaps between different types are filled with entries
 * for the default factory.
 */

/// Initialize factory
ASTFactory::ASTFactory()
: default_factory_descriptor(ANTLR_USE_NAMESPACE(std)make_pair(CommonAST::TYPE_NAME,&CommonAST::factory))
{
	nodeFactories.resize( Token::MIN_USER_TYPE, &default_factory_descriptor );
}

/** Initialize factory with a non default node type.
 * factory_node_name should be the name of the AST node type the factory
 * generates. (should exist during the existance of this ASTFactory instance)
 */
ASTFactory::ASTFactory( const char* factory_node_name, factory_type fact )
: default_factory_descriptor(ANTLR_USE_NAMESPACE(std)make_pair(factory_node_name, fact))
{
	nodeFactories.resize( Token::MIN_USER_TYPE, &default_factory_descriptor );
}

/// Delete ASTFactory
ASTFactory::~ASTFactory()
{
	factory_descriptor_list::iterator i = nodeFactories.begin();

	while( i != nodeFactories.end() )
	{
		if( *i != &default_factory_descriptor )
			delete *i;
		i++;
	}
}

/// Register a factory for a given AST type
void ASTFactory::registerFactory( int type, const char* ast_name, factory_type factory )
{
	// check validity of arguments...
	if( type < Token::MIN_USER_TYPE )
		throw ANTLRException("Internal parser error invalid type passed to RegisterFactory");
	if( factory == 0 )
		throw ANTLRException("Internal parser error 0 factory passed to RegisterFactory");

	// resize up to and including 'type' and initalize any gaps to default
	// factory.
	if( nodeFactories.size() < (static_cast<unsigned int>(type)+1) )
		nodeFactories.resize( type+1, &default_factory_descriptor );

	// And add new thing..
	nodeFactories[type] = new ANTLR_USE_NAMESPACE(std)pair<const char*, factory_type>( ast_name, factory );
}

void ASTFactory::setMaxNodeType( int type )
{
	if( nodeFactories.size() < (static_cast<unsigned int>(type)+1) )
		nodeFactories.resize( type+1, &default_factory_descriptor );
}

/** Create a new empty AST node; if the user did not specify
 *  an AST node type, then create a default one: CommonAST.
 */
RefAST ASTFactory::create()
{
	RefAST node = nodeFactories[0]->second();
	node->setType(Token::INVALID_TYPE);
	return node;
}

RefAST ASTFactory::create(int type)
{
	RefAST t = nodeFactories[type]->second();
	t->initialize(type,"");
	return t;
}

RefAST ASTFactory::create(int type, const ANTLR_USE_NAMESPACE(std)string& txt)
{
	RefAST t = nodeFactories[type]->second();
	t->initialize(type,txt);
	return t;
}

#ifdef ANTLR_SUPPORT_XML
RefAST ASTFactory::create(const ANTLR_USE_NAMESPACE(std)string& type_name, ANTLR_USE_NAMESPACE(std)istream& infile )
{
	factory_descriptor_list::iterator fact = nodeFactories.begin();

	while( fact != nodeFactories.end() )
	{
		if( type_name == (*fact)->first )
		{
			RefAST t = (*fact)->second();
			t->initialize(infile);
			return t;
		}
		fact++;
	}

	string error = "ASTFactory::create: Unknown AST type '" + type_name + "'";
	throw ANTLRException(error);
}
#endif

/** Create a new empty AST node; if the user did not specify
 *  an AST node type, then create a default one: CommonAST.
 */
RefAST ASTFactory::create(RefAST tr)
{
	if (!tr)
		return nullAST;

//	cout << "create(tr)" << endl;

	RefAST t = nodeFactories[tr->getType()]->second();
	t->initialize(tr);
	return t;
}

RefAST ASTFactory::create(RefToken tok)
{
//	cout << "create( tok="<< tok->getType() << ", " << tok->getText() << ")" << nodeFactories.size() << endl;
	RefAST t = nodeFactories[tok->getType()]->second();
	t->initialize(tok);
	return t;
}

/** Add a child to the current AST */
void ASTFactory::addASTChild(ASTPair& currentAST, RefAST child)
{
	if (child)
	{
		if (!currentAST.root)
		{
			// Make new child the current root
			currentAST.root = child;
		}
		else
		{
			if (!currentAST.child)
			{
				// Add new child to current root
				currentAST.root->setFirstChild(child);
			}
			else
			{
				currentAST.child->setNextSibling(child);
			}
		}
		// Make new child the current child
		currentAST.child = child;
		currentAST.advanceChildToEnd();
	}
}

/** Deep copy a single node. This function the new clone() methods in the AST
 * interface. Returns nullAST if t is null.
 */
RefAST ASTFactory::dup(RefAST t)
{
	if( t )
		return t->clone();
	else
		return RefAST(nullASTptr);
}

/** Duplicate tree including siblings of root. */
RefAST ASTFactory::dupList(RefAST t)
{
	RefAST result = dupTree(t);         // if t == null, then result==null
	RefAST nt = result;

	while( t )
	{												// for each sibling of the root
		t = t->getNextSibling();
		nt->setNextSibling(dupTree(t));	// dup each subtree, building new tree
		nt = nt->getNextSibling();
	}
	return result;
}

/** Duplicate a tree, assuming this is a root node of a tree
 * duplicate that node and what's below; ignore siblings of root node.
 */
RefAST ASTFactory::dupTree(RefAST t)
{
	RefAST result = dup(t);		// make copy of root
	// copy all children of root.
	if( t )
		result->setFirstChild( dupList(t->getFirstChild()) );
	return result;
}

/** Make a tree from a list of nodes.  The first element in the
 * array is the root.  If the root is null, then the tree is
 * a simple list not a tree.  Handles null children nodes correctly.
 * For example, make(a, b, null, c) yields tree (a b c).  make(null,a,b)
 * yields tree (nil a b).
 */
RefAST ASTFactory::make(ANTLR_USE_NAMESPACE(std)vector<RefAST>& nodes)
{
	if ( nodes.size() == 0 )
		return RefAST(nullASTptr);

	RefAST root = nodes[0];
	RefAST tail = RefAST(nullASTptr);

	if( root )
		root->setFirstChild(RefAST(nullASTptr));	// don't leave any old pointers set

	// link in children;
	for( unsigned int i = 1; i < nodes.size(); i++ )
	{
		if ( nodes[i] == 0 )		// ignore null nodes
			continue;

		if ( root == 0 )			// Set the root and set it up for a flat list
			root = tail = nodes[i];
		else if ( tail == 0 )
		{
			root->setFirstChild(nodes[i]);
			tail = root->getFirstChild();
		}
		else
		{
			tail->setNextSibling(nodes[i]);
			tail = tail->getNextSibling();
		}

		if( tail )	// RK: I cannot fathom why this missing check didn't bite anyone else...
		{
			// Chase tail to last sibling
			while (tail->getNextSibling())
				tail = tail->getNextSibling();
		}
	}

	return root;
}

/** Make a tree from a list of nodes, where the nodes are contained
 * in an ASTArray object
 */
RefAST ASTFactory::make(ASTArray* nodes)
{
	RefAST ret = make(nodes->array);
	delete nodes;
	return ret;
}

/// Make an AST the root of current AST
void ASTFactory::makeASTRoot( ASTPair& currentAST, RefAST root )
{
	if (root)
	{
		// Add the current root as a child of new root
		root->addChild(currentAST.root);
		// The new current child is the last sibling of the old root
		currentAST.child = currentAST.root;
		currentAST.advanceChildToEnd();
		// Set the new root
		currentAST.root = root;
	}
}

void ASTFactory::setASTNodeFactory( const char* factory_node_name,
											   factory_type factory )
{
	default_factory_descriptor.first = factory_node_name;
	default_factory_descriptor.second = factory;
}

#ifdef ANTLR_SUPPORT_XML
bool ASTFactory::checkCloseTag( ANTLR_USE_NAMESPACE(std)istream& in )
{
	char ch;

	if( in.get(ch) )
	{
		if( ch == '<' )
		{
			char ch2;
			if( in.get(ch2) )
			{
				if( ch2 == '/' )
				{
					in.putback(ch2);
					in.putback(ch);
					return true;
				}
				in.putback(ch2);
				in.putback(ch);
				return false;
			}
		}
		in.putback(ch);
		return false;
	}
	return false;
}

void ASTFactory::loadChildren( ANTLR_USE_NAMESPACE(std)istream& infile,
										 RefAST current )
{
	char ch;

	for(;;)			// for all children of this node....
	{
		eatwhite(infile);

		infile.get(ch);	// '<'
		if( ch != '<' )
		{
			string error = "Invalid XML file... no '<' found (";
			error += ch + ")";
			throw IOException(error);
		}

		infile.get(ch);		// / or text....

		if( ch == '/' )		// check for close tag...
		{
			string temp;

			// read until '>' and see if it matches the open tag... if not trouble
			temp = read_identifier( infile );

			if( strcmp(temp.c_str(), current->typeName() ) != 0 )
			{
				string error = "Invalid XML file... close tag does not match start tag: ";
				error += current->typeName();
				error += " closed by " + temp;
				throw IOException(error);
			}

			infile.get(ch);	// must be a '>'

			if( ch != '>' )
			{
				string error = "Invalid XML file... no '>' found (";
				error += ch + ")";
				throw IOException(error);
			}
			// close tag => exit loop
			break;
		}

		// put our 'look ahead' back where it came from
		infile.putback(ch);
		infile.putback('<');

		// and recurse into the tree...
		RefAST child = LoadAST(infile);

		current->addChild( child );
	}
}

void ASTFactory::loadSiblings(ANTLR_USE_NAMESPACE(std)istream& infile,
										RefAST current )
{
	for(;;)
	{
		eatwhite(infile);

		if( infile.eof() )
			break;

		if( checkCloseTag(infile) )
			break;

		RefAST sibling = LoadAST(infile);
		current->setNextSibling(sibling);
	}
}

RefAST ASTFactory::LoadAST( ANTLR_USE_NAMESPACE(std)istream& infile )
{
	RefAST current = nullAST;
	char ch;

	eatwhite(infile);

	if( !infile.get(ch) )
		return nullAST;

	if( ch != '<' )
	{
		string error = "Invalid XML file... no '<' found (";
		error += ch + ")";
		throw IOException(error);
	}

	string ast_type = read_identifier(infile);

	// create the ast of type 'ast_type'
	current = create( ast_type, infile );
	if( current == nullAST )
	{
		string error = "Unsuported AST type: " + ast_type;
		throw IOException(error);
	}

	eatwhite(infile);

	infile.get(ch);

	// now if we have a '/' here it's a single node. If it's a '>' we get
	// a tree with children

	if( ch == '/' )
	{
		infile.get(ch);		// get the closing '>'
		if( ch != '>' )
		{
			string error = "Invalid XML file... no '>' found after '/' (";
			error += ch + ")";
			throw IOException(error);
		}

		// get the rest on this level
		loadSiblings( infile, current );

		return current;
	}

	// and finaly see if we got the close tag...
	if( ch != '>' )
	{
		string error = "Invalid XML file... no '>' found (";
		error += ch + ")";
		throw IOException(error);
	}

	// handle the ones below this level..
	loadChildren( infile, current );

	// load the rest on this level...
	loadSiblings( infile, current );

	return current;
}
#endif // ANTLR_SUPPORT_XML

#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
}
#endif

/* Heterogeneous AST/XML-I/O ramblings...
 *
 * So there is some heterogeneous AST support....
 * basically in the code generators a new custom ast is generated without
 * going throug the factory. It also expects the RefXAST to be defined.
 *
 * Is it maybe better to register all AST types with the ASTFactory class
 * together with the respective factory methods.
 *
 * More and more I get the impression that hetero ast was a kindoff hack
 * on top of ANTLR's normal AST system.
 *
 * The heteroast stuff will generate trouble for all astFactory.create( ... )
 * invocations. Most of this is handled via getASTCreateString methods in the
 * codegenerator. At the moment getASTCreateString(GrammarAtom, String) has
 * slightly to little info to do it's job (ok the hack that is in now
 * works, but it's an ugly hack)
 *
 * An extra caveat is the 'nice' action.g thing. Which also judiciously calls
 * getASTCreateString methods because it handles the #( ... ) syntax.
 * And converts that to ASTFactory calls.
 *
 *
 */