KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > persistence > antlr > ASTFactory


1 package persistence.antlr;
2
3 /* ANTLR Translator Generator
4  * Project led by Terence Parr at http://www.jGuru.com
5  * Software rights: http://www.antlr.org/license.html
6  *
7  */

8
9 import persistence.antlr.collections.AST;
10 import persistence.antlr.collections.impl.ASTArray;
11
12 import java.util.Hashtable JavaDoc;
13 import java.lang.reflect.Constructor JavaDoc;
14
15 /** AST Support code shared by TreeParser and Parser.
16  * We use delegation to share code (and have only one
17  * bit of code to maintain) rather than subclassing
18  * or superclassing (forces AST support code to be
19  * loaded even when you don't want to do AST stuff).
20  *
21  * Typically, setASTNodeType is used to specify the
22  * homogeneous type of node to create, but you can override
23  * create to make heterogeneous nodes etc...
24  */

25 public class ASTFactory {
26     /** Name of AST class to create during tree construction.
27      * Null implies that the create method should create
28      * a default AST type such as CommonAST. This is for
29      * homogeneous nodes.
30      */

31     protected String JavaDoc theASTNodeType = null;
32     protected Class JavaDoc theASTNodeTypeClass = null;
33
34     /** How to specify the classname to create for a particular
35      * token type. Note that ANTLR allows you to say, for example,
36      *
37         tokens {
38          PLUS<AST=PLUSNode>;
39          ...
40         }
41      *
42      * and it tracks everything statically. #[PLUS] will make you
43      * a PLUSNode w/o use of this table.
44      *
45      * For tokens that ANTLR cannot track statically like #[i],
46      * you can use this table to map PLUS (Integer) -> PLUSNode (Class)
47      * etc... ANTLR sets the class map from the tokens {...} section
48      * via the ASTFactory(Hashtable) ctor in persistence.antlr.Parser.
49      */

50     protected Hashtable JavaDoc tokenTypeToASTClassMap = null;
51
52     public ASTFactory() {
53     }
54
55     /** Create factory with a specific mapping from token type
56      * to Java AST node type. Your subclasses of ASTFactory
57      * can override and reuse the map stuff.
58      */

59     public ASTFactory(Hashtable JavaDoc tokenTypeToClassMap) {
60         setTokenTypeToASTClassMap(tokenTypeToClassMap);
61     }
62
63     /** Specify an "override" for the Java AST object created for a
64      * specific token. It is provided as a convenience so
65      * you can specify node types dynamically. ANTLR sets
66      * the token type mapping automatically from the tokens{...}
67      * section, but you can change that mapping with this method.
68      * ANTLR does it's best to statically determine the node
69      * type for generating parsers, but it cannot deal with
70      * dynamic values like #[LT(1)]. In this case, it relies
71      * on the mapping. Beware differences in the tokens{...}
72      * section and what you set via this method. Make sure
73      * they are the same.
74      *
75      * Set className to null to remove the mapping.
76      *
77      * @since 2.7.2
78      */

79     public void setTokenTypeASTNodeType(int tokenType, String JavaDoc className)
80         throws IllegalArgumentException JavaDoc
81     {
82         if ( tokenTypeToASTClassMap==null ) {
83             tokenTypeToASTClassMap = new Hashtable JavaDoc();
84         }
85         if ( className==null ) {
86             tokenTypeToASTClassMap.remove(new Integer JavaDoc(tokenType));
87             return;
88         }
89         Class JavaDoc c = null;
90         try {
91             c = Class.forName(className);
92             tokenTypeToASTClassMap.put(new Integer JavaDoc(tokenType), c);
93         }
94         catch (Exception JavaDoc e) {
95             throw new IllegalArgumentException JavaDoc("Invalid class, "+className);
96         }
97     }
98
99     /** For a given token type, what is the AST node object type to create
100      * for it?
101      * @since 2.7.2
102      */

103     public Class JavaDoc getASTNodeType(int tokenType) {
104         // try node specific class
105
if ( tokenTypeToASTClassMap!=null ) {
106             Class JavaDoc c = (Class JavaDoc)tokenTypeToASTClassMap.get(new Integer JavaDoc(tokenType));
107             if ( c!=null ) {
108                 return c;
109             }
110         }
111
112         // try a global specified class
113
if (theASTNodeTypeClass != null) {
114             return theASTNodeTypeClass;
115         }
116
117         // default to the common type
118
return CommonAST.class;
119     }
120
121     /** Add a child to the current AST */
122     public void addASTChild(ASTPair currentAST, AST child) {
123         if (child != null) {
124             if (currentAST.root == null) {
125                 // Make new child the current root
126
currentAST.root = child;
127             }
128             else {
129                 if (currentAST.child == null) {
130                     // Add new child to current root
131
currentAST.root.setFirstChild(child);
132                 }
133                 else {
134                     currentAST.child.setNextSibling(child);
135                 }
136             }
137             // Make new child the current child
138
currentAST.child = child;
139             currentAST.advanceChildToEnd();
140         }
141     }
142
143     /** Create a new empty AST node; if the user did not specify
144      * an AST node type, then create a default one: CommonAST.
145      */

146     public AST create() {
147         return create(Token.INVALID_TYPE);
148     }
149
150     public AST create(int type) {
151         Class JavaDoc c = getASTNodeType(type);
152         AST t = create(c);
153         if ( t!=null ) {
154             t.initialize(type, "");
155         }
156         return t;
157     }
158
159     public AST create(int type, String JavaDoc txt) {
160         AST t = create(type);
161         if ( t!=null ) {
162             t.initialize(type, txt);
163         }
164         return t;
165     }
166
167     /** Create an AST node with the token type and text passed in, but
168      * with a specific Java object type. Typically called when you
169      * say @[PLUS,"+",PLUSNode] in an antlr action.
170      * @since 2.7.2
171      */

172     public AST create(int type, String JavaDoc txt, String JavaDoc className) {
173         AST t = create(className);
174         if ( t!=null ) {
175             t.initialize(type, txt);
176         }
177         return t;
178     }
179
180     /** Create a new empty AST node; if the user did not specify
181      * an AST node type, then create a default one: CommonAST.
182      */

183     public AST create(AST tr) {
184         if (tr == null) return null; // create(null) == null
185
AST t = create(tr.getType());
186         if ( t!=null ) {
187             t.initialize(tr);
188         }
189         return t;
190     }
191
192     public AST create(Token tok) {
193         AST t = create(tok.getType());
194         if ( t!=null ) {
195             t.initialize(tok);
196         }
197         return t;
198     }
199
200     /** ANTLR generates reference to this when you reference a token
201      * that has a specified heterogeneous AST node type. This is
202      * also a special case node creation routine for backward
203      * compatibility. Before, ANTLR generated "new T(tokenObject)"
204      * and so I must call the appropriate constructor not T().
205      *
206      * @since 2.7.2
207      */

208     public AST create(Token tok, String JavaDoc className) {
209         AST t = createUsingCtor(tok,className);
210         return t;
211     }
212
213     /**
214      * @since 2.7.2
215      */

216     public AST create(String JavaDoc className) {
217         Class JavaDoc c = null;
218         try {
219             c = Class.forName(className);
220         }
221         catch (Exception JavaDoc e) {
222             throw new IllegalArgumentException JavaDoc("Invalid class, "+className);
223         }
224         return create(c);
225     }
226
227     /**
228      * @since 2.7.2
229      */

230     protected AST createUsingCtor(Token token, String JavaDoc className) {
231         Class JavaDoc c = null;
232         AST t = null;
233         try {
234             c = Class.forName(className);
235             Class JavaDoc[] tokenArgType = new Class JavaDoc[] { persistence.antlr.Token.class };
236             try {
237                 Constructor JavaDoc ctor = c.getConstructor(tokenArgType);
238                 t = (AST)ctor.newInstance(new Object JavaDoc[]{token}); // make a new one
239
}
240             catch (NoSuchMethodException JavaDoc e){
241                 // just do the regular thing if you can't find the ctor
242
// Your AST must have default ctor to use this.
243
t = create(c);
244                 if ( t!=null ) {
245                     t.initialize(token);
246                 }
247             }
248         }
249         catch (Exception JavaDoc e) {
250             throw new IllegalArgumentException JavaDoc("Invalid class or can't make instance, "+className);
251         }
252         return t;
253     }
254
255     /**
256      * @since 2.7.2
257      */

258     protected AST create(Class JavaDoc c) {
259         AST t = null;
260         try {
261             t = (AST)c.newInstance(); // make a new one
262
}
263         catch (Exception JavaDoc e) {
264             error("Can't create AST Node " + c.getName());
265             return null;
266         }
267         return t;
268     }
269
270     /** Copy a single node with same Java AST objec type.
271      * Ignore the tokenType->Class mapping since you know
272      * the type of the node, t.getClass(), and doing a dup.
273      *
274      * clone() is not used because we want all AST creation
275      * to go thru the factory so creation can be
276      * tracked. Returns null if t is null.
277      */

278     public AST dup(AST t) {
279         if ( t==null ) {
280             return null;
281         }
282         AST dup_t = create(t.getClass());
283         dup_t.initialize(t);
284         return dup_t;
285     }
286
287     /** Duplicate tree including siblings of root. */
288     public AST dupList(AST t) {
289         AST result = dupTree(t); // if t == null, then result==null
290
AST nt = result;
291         while (t != null) { // for each sibling of the root
292
t = t.getNextSibling();
293             nt.setNextSibling(dupTree(t)); // dup each subtree, building new tree
294
nt = nt.getNextSibling();
295         }
296         return result;
297     }
298
299     /**Duplicate a tree, assuming this is a root node of a tree--
300      * duplicate that node and what's below; ignore siblings of root node.
301      */

302     public AST dupTree(AST t) {
303         AST result = dup(t); // make copy of root
304
// copy all children of root.
305
if (t != null) {
306             result.setFirstChild(dupList(t.getFirstChild()));
307         }
308         return result;
309     }
310
311     /** Make a tree from a list of nodes. The first element in the
312      * array is the root. If the root is null, then the tree is
313      * a simple list not a tree. Handles null children nodes correctly.
314      * For example, build(a, b, null, c) yields tree (a b c). build(null,a,b)
315      * yields tree (nil a b).
316      */

317     public AST make(AST[] nodes) {
318         if (nodes == null || nodes.length == 0) return null;
319         AST root = nodes[0];
320         AST tail = null;
321         if (root != null) {
322             root.setFirstChild(null); // don't leave any old pointers set
323
}
324         // link in children;
325
for (int i = 1; i < nodes.length; i++) {
326             if (nodes[i] == null) continue; // ignore null nodes
327
if (root == null) {
328                 // Set the root and set it up for a flat list
329
root = tail = nodes[i];
330             }
331             else if (tail == null) {
332                 root.setFirstChild(nodes[i]);
333                 tail = root.getFirstChild();
334             }
335             else {
336                 tail.setNextSibling(nodes[i]);
337                 tail = tail.getNextSibling();
338             }
339             // Chase tail to last sibling
340
while (tail.getNextSibling() != null) {
341                 tail = tail.getNextSibling();
342             }
343         }
344         return root;
345     }
346
347     /** Make a tree from a list of nodes, where the nodes are contained
348      * in an ASTArray object
349      */

350     public AST make(ASTArray nodes) {
351         return make(nodes.array);
352     }
353
354     /** Make an AST the root of current AST */
355     public void makeASTRoot(ASTPair currentAST, AST root) {
356         if (root != null) {
357             // Add the current root as a child of new root
358
root.addChild(currentAST.root);
359             // The new current child is the last sibling of the old root
360
currentAST.child = currentAST.root;
361             currentAST.advanceChildToEnd();
362             // Set the new root
363
currentAST.root = root;
364         }
365     }
366
367     public void setASTNodeClass(String JavaDoc t) {
368         theASTNodeType = t;
369         try {
370             theASTNodeTypeClass = Class.forName(t); // get class def
371
}
372         catch (Exception JavaDoc e) {
373             // either class not found,
374
// class is interface/abstract, or
375
// class or initializer is not accessible.
376
error("Can't find/access AST Node type" + t);
377         }
378     }
379
380     /** Specify the type of node to create during tree building.
381      * @deprecated since 2.7.1
382      */

383     public void setASTNodeType(String JavaDoc t) {
384         setASTNodeClass(t);
385     }
386
387     public Hashtable JavaDoc getTokenTypeToASTClassMap() {
388         return tokenTypeToASTClassMap;
389     }
390
391     public void setTokenTypeToASTClassMap(Hashtable JavaDoc tokenTypeToClassMap) {
392         this.tokenTypeToASTClassMap = tokenTypeToClassMap;
393     }
394
395     /** To change where error messages go, can subclass/override this method
396      * and then setASTFactory in Parser and TreeParser. This method removes
397      * a prior dependency on class persistence.antlr.Tool.
398      */

399     public void error(String JavaDoc e) {
400         System.err.println(e);
401     }
402 }
403
Popular Tags