1 package com.sun.gluegen.cgram;
2 
3 import antlr.collections.AST;
4 import antlr.CommonAST;
5 import antlr.Token;
6 import java.lang.reflect.*;
7 import java.util.Hashtable;
8 import java.util.Enumeration;
9 
10 /**
11   Class TNode is an implementation of the AST interface
12   and adds many useful features:
13 
14   It is double-linked for reverse searching.
15   (this is currently incomplete, in that method doubleLink() must
16   be called after any changes to the tree to maintain the
17   reverse links).
18 
19   It can store a definition node (defNode), so that nodes such
20   as scoped names can refer to the node that defines the name.
21 
22   It stores line numbers for nodes.
23 
24   Searches for parents and children of a tree can be done
25   based on their type.
26 
27   The tree can be printed to System.out using a lisp-style syntax.
28 
29 
30 
31  */
32 public class TNode extends CommonAST {
33   protected int ttype;
34   protected String text;
35   protected int lineNum = 0;
36   protected TNode defNode;
37   protected TNode up;
38   protected TNode left;
39   protected boolean marker = false;
40   protected Hashtable attributes = null;
41   static String tokenVocabulary;
42 
43 
44 
45 
46   /** Set the token vocabulary to a tokentypes class
47       generated by antlr.
48   */
setTokenVocabulary(String s)49   public static void setTokenVocabulary(String s) {
50     tokenVocabulary = s;
51   }
52 
53 
initialize(Token token)54 public void initialize(Token token) {
55         CToken tok = (CToken) token;
56         setText(tok.getText());
57         setType(tok.getType());
58         setLineNum(tok.getLine());
59         setAttribute("source", tok.getSource());
60         setAttribute("tokenNumber", new Integer(tok.getTokenNumber()));
61 }
initialize(AST tr)62 public void initialize(AST tr) {
63         TNode t = (TNode) tr;
64         setText(t.getText());
65         setType(t.getType());
66         setLineNum(t.getLineNum());
67         setDefNode(t.getDefNode());
68         this.attributes = t.getAttributesTable();
69 }
70 
71 
72   /** Get the token type for this node */
getType()73   public int getType() { return ttype; }
74 
75   /** Set the token type for this node */
setType(int ttype_)76   public void setType(int ttype_) {
77     ttype = ttype_;
78   }
79 
80   /** Get the marker value for this node.
81    This member is a general-use marker.
82    */
getMarker()83   public boolean getMarker() { return marker; }
84 
85   /** Set the marker value for this node.
86    This property is a general-use boolean marker.
87    */
setMarker(boolean marker_)88   public void setMarker(boolean marker_) {
89     marker = marker_;
90   }
91 
92   /** get the hashtable that holds attribute values.
93    */
getAttributesTable()94   public Hashtable getAttributesTable() {
95     if(attributes == null)
96       attributes = new Hashtable(7);
97     return attributes;
98   }
99 
100   /** set an attribute in the attribute table.
101    */
setAttribute(String attrName, Object value)102   public void setAttribute(String attrName, Object value) {
103     if(attributes == null)
104       attributes = new Hashtable(7);
105     attributes.put(attrName,value);
106   }
107 
108   /** lookup the attribute name in the attribute table.
109     If the value does not exist, it returns null.
110     */
getAttribute(String attrName)111   public Object getAttribute(String attrName) {
112     if(attributes == null)
113       return null;
114     else
115       return attributes.get(attrName);
116   }
117 
118   /** Get the line number for this node.
119    If the line number is 0, search for a non-zero line num among children */
getLineNum()120   public int getLineNum() {
121     if(lineNum != 0)
122       return lineNum;
123     else
124       if(down == null)
125         return lineNum;
126       else
127         return ((TNode)down).getLocalLineNum();
128   }
129 
getLocalLineNum()130   public int getLocalLineNum() {
131     if(lineNum != 0)
132       return lineNum;
133     else
134       if(down == null)
135         if(right == null)
136           return lineNum;
137         else
138           return ((TNode)right).getLocalLineNum();
139       else
140         return ((TNode)down).getLocalLineNum();
141   }
142 
143   /** Set the line number for this node */
setLineNum(int lineNum_)144   public void setLineNum(int lineNum_) {
145     lineNum = lineNum_;
146   }
147 
148   /** Get the token text for this node */
getText()149   public String getText() { return text; }
150 
151   /** Set the token text for this node */
setText(String text_)152   public void setText(String text_) {
153     text = text_;
154   }
155 
156   /** Returns the text for this node and all children */
getAllChildrenText()157   public String getAllChildrenText() {
158     StringBuffer buf = new StringBuffer();
159     buf.append(getText());
160     for (TNode node = (TNode) getFirstChild(); node != null; node = (TNode) node.getNextSibling()) {
161       buf.append(node.getText());
162     }
163     return buf.toString();
164   }
165 
166   /** return the last child of this node, or null if there is none */
getLastChild()167   public TNode getLastChild() {
168     TNode down = (TNode)getFirstChild();
169     if(down != null)
170       return down.getLastSibling();
171     else
172       return null;
173   }
174 
175   /** return the last sibling of this node, which is
176       this if the next sibling is null */
getLastSibling()177   public TNode getLastSibling() {
178     TNode next = (TNode)getNextSibling();
179     if(next != null)
180       return next.getLastSibling();
181     else
182       return this;
183   }
184 
185   /** return the first sibling of this node, which is
186       this if the prev sibling is null */
getFirstSibling()187   public TNode getFirstSibling() {
188     TNode prev = (TNode)left;
189     if(prev != null)
190       return prev.getFirstSibling();
191     else
192       return this;
193   }
194 
195 
196   /** return the parent node of this node */
getParent()197   public TNode getParent() {
198     return (TNode)getFirstSibling().up;
199   }
200 
201 
202   /** add the new node as a new sibling, inserting it ahead of any
203     existing next sibling.  This method maintains double-linking.
204     if node is null, nothing happens.  If the node has siblings,
205     then they are added in as well.
206     */
addSibling(AST node)207   public void addSibling(AST node) {
208     if(node == null) return;
209     TNode next = (TNode)right;
210     right = (TNode)node;
211     ((TNode)node).left = this;
212     TNode nodeLastSib = ((TNode)node).getLastSibling();
213     nodeLastSib.right = next;
214     if(next != null)
215       next.left = nodeLastSib;
216   }
217 
218 
219   /** return the number of children of this node */
numberOfChildren()220   public int numberOfChildren() {
221     int count = 0;
222     AST child = getFirstChild();
223     while(child != null) {
224       count++;
225       child = child.getNextSibling();
226     }
227     return count;
228   }
229 
230 
231   /** remove this node from the tree, resetting sibling and parent
232     pointers as necessary.  This method maintains double-linking */
removeSelf()233   public void removeSelf() {
234     TNode parent = (TNode)up;
235     TNode prev = (TNode)left;
236     TNode next = (TNode)right;
237 
238     if(parent != null) {
239       parent.down = next;
240       if(next != null) {
241         next.up = parent;
242         next.left = prev;    // which should be null
243       }
244     }
245     else {
246      if(prev != null)
247       prev.right = next;
248      if(next != null)
249        next.left = prev;
250     }
251   }
252 
253 
254   /** return the def node for this node */
getDefNode()255   public TNode getDefNode() {
256       return defNode;
257   }
258 
259   /** set the def node for this node */
setDefNode(TNode n)260   public void setDefNode(TNode n) {
261     defNode = n;
262   }
263 
264 
265   /** return a deep copy of this node, and all sub nodes.
266     New tree is doubleLinked, with no parent or siblings.
267     Marker value is not copied!
268     */
deepCopy()269   public TNode deepCopy() {
270     TNode copy = new TNode();
271     copy.ttype = ttype;
272     copy.text = text;
273     copy.lineNum = lineNum;
274     copy.defNode = defNode;
275     if(attributes != null)
276       copy.attributes = (Hashtable)attributes.clone();
277     if(down != null)
278       copy.down = ((TNode)down).deepCopyWithRightSiblings();
279     copy.doubleLink();
280     return copy;
281   }
282 
283 
284   /** return a deep copy of this node, all sub nodes,
285     and right siblings.
286     New tree is doubleLinked, with no parent or left siblings.
287     defNode is not copied  */
deepCopyWithRightSiblings()288   public TNode deepCopyWithRightSiblings() {
289     TNode copy = new TNode();
290     copy.ttype = ttype;
291     copy.text = text;
292     copy.lineNum = lineNum;
293     copy.defNode = defNode;
294     if(attributes != null)
295       copy.attributes = (Hashtable)attributes.clone();
296     if(down != null)
297       copy.down = ((TNode)down).deepCopyWithRightSiblings();
298     if(right != null)
299       copy.right = ((TNode)right).deepCopyWithRightSiblings();
300     copy.doubleLink();
301     return copy;
302   }
303 
304 
305   /** return a short string representation of the node */
toString()306   public String toString() {
307     StringBuffer str = new StringBuffer( getNameForType(getType()) +
308            "[" + getText() + ", " + "]");
309 
310      if(this.getLineNum() != 0)
311        str.append(" line:" + (this.getLineNum() ) );
312 
313      Enumeration keys = (this.getAttributesTable().keys());
314      while (keys.hasMoreElements()) {
315        String key = (String) keys.nextElement();
316        str.append(" " + key + ":" + (this.getAttribute(key)));
317      }
318 
319     return str.toString();
320   }
321 
322 
323   /** print given tree to System.out */
printTree(AST t)324   public static void printTree(AST t) {
325        if (t == null) return;
326        printASTNode(t,0);
327        System.out.print("\n");
328   }
329 
330 
331   /** protected method that does the work of printing */
printASTNode(AST t, int indent)332   protected static void printASTNode(AST t, int indent) {
333      AST child1, next;
334      child1 = t.getFirstChild();
335 
336     System.out.print("\n");
337      for(int i = 0; i < indent; i++)
338        System.out.print("   ");
339 
340      if(child1 != null)
341         System.out.print("(");
342 
343      String s = t.getText();
344      if(s != null && s.length() > 0) {
345        System.out.print(getNameForType(t.getType()));
346        System.out.print(": \"" + s + "\"");
347      }
348      else
349        System.out.print(getNameForType(t.getType()));
350      if(((TNode)t).getLineNum() != 0)
351        System.out.print(" line:" + ((TNode)t).getLineNum() );
352 
353      Enumeration keys = ((TNode)t).getAttributesTable().keys();
354      while (keys.hasMoreElements()) {
355        String key = (String) keys.nextElement();
356        System.out.print(" " + key + ":" + ((TNode)t).getAttribute(key));
357      }
358      TNode def = ((TNode)t).getDefNode();
359      if(def != null)
360        System.out.print("[" + getNameForType(def.getType()) + "]");
361 
362 
363      if(child1 != null) {
364         printASTNode(child1,indent + 1);
365 
366         System.out.print("\n");
367         for(int i = 0; i < indent; i++)
368            System.out.print("   ");
369         System.out.print(")");
370      }
371 
372      next = t.getNextSibling();
373      if(next != null) {
374         printASTNode(next,indent);
375      }
376   }
377 
378   /** converts an int tree token type to a name.
379       Does this by reflecting on nsdidl.IDLTreeTokenTypes,
380       and is dependent on how ANTLR 2.00 outputs that class. */
getNameForType(int t)381   public static String getNameForType(int t) {
382     try{
383       Class c = Class.forName(tokenVocabulary);
384       Field[] fields = c.getDeclaredFields();
385       if(t-2 < fields.length)
386         return fields[t-2].getName();
387     } catch (Exception e) { System.out.println(e); }
388     return "unfoundtype: " + t;
389   }
390 
391 
392   /** set up reverse links between this node and its first
393      child and its first sibling, and link those as well */
doubleLink()394   public void doubleLink() {
395     TNode right = (TNode)getNextSibling();
396     if(right != null) {
397       right.left = this;
398       right.doubleLink();
399     }
400     TNode down = (TNode)getFirstChild();
401     if(down != null) {
402       down.up = this;
403       down.doubleLink();
404     }
405   }
406 
407   /** find first parent of the given type,
408     return null on failure */
parentOfType(int type)409   public TNode parentOfType(int type) {
410     if(up == null) {
411       if(left == null)
412         return null;
413       else
414         return left.parentOfType(type);
415     }
416     if(up.getType() == type)
417       return up;
418     return up.parentOfType(type);
419   }
420 
421   /** find the first child of the node
422     of the given type, return null on failure */
firstChildOfType(int type)423   public TNode firstChildOfType(int type) {
424     TNode down = (TNode)getFirstChild();
425     if(down == null)
426       return null;
427     if(down.getType() == type)
428       return down;
429     return down.firstSiblingOfType(type);
430   }
431 
432   /** find the first sibling of the node
433     of the given type, return null on failure */
firstSiblingOfType(int type)434   public TNode firstSiblingOfType(int type) {
435     TNode right = (TNode)getNextSibling();
436     if(right == null)
437       return null;
438     if(right.getType() == type)
439       return right;
440     return right.firstSiblingOfType(type);
441   }
442 
443 }
444