1	package antlr;
2	
3	/**
4	 * A Child-Sibling Tree.
5	 *
6	 * A tree with PLUS at the root and with two children 3 and 4 is
7	 * structured as:
8	 *
9	 *		PLUS
10	 *		  |
11	 *		  3 -- 4
12	 *
13	 * and can be specified easily in LISP notation as
14	 *
15	 * (PLUS 3 4)
16	 *
17	 * where every '(' starts a new subtree.
18	 *
19	 * These trees are particular useful for translators because of
20	 * the flexibility of the children lists.  They are also very easy
21	 * to walk automatically, whereas trees with specific children
22	 * reference fields can't easily be walked automatically.
23	 *
24	 * This class contains the basic support for an AST.
25	 * Most people will create ASTs that are subclasses of
26	 * BaseAST or of CommonAST.
27	 */
28	import antlr.collections.AST;
29	import antlr.collections.ASTEnumeration;
30	import antlr.collections.impl.ASTEnumerator;
31	import antlr.collections.impl.Vector;
32	
33	public abstract class BaseAST implements AST {
34		protected BaseAST down;
35		protected BaseAST right;
36	
37		private static boolean verboseStringConversion = false;
38		private static String[] tokenNames = null;
39		
40		/**Add a node to the end of the child list for this node */
41		public void addChild(AST node) {
42			if ( node==null ) return;
43			BaseAST t = this.down;
44			if ( t!=null ) {
45				while ( t.right!=null ) {
46					t = t.right;
47				}
48				t.right = (BaseAST)node;
49			}
50			else {
51				this.down = (BaseAST)node;
52			}
53		}
54	private void doWorkForFindAll(Vector v, AST target, boolean partialMatch) {
55		AST sibling;
56		
57		// Start walking sibling lists, looking for matches.
58	siblingWalk:
59		for (sibling=this;
60			  sibling!=null;
61			  sibling=sibling.getNextSibling())
62		{
63			if ( (partialMatch && sibling.equalsTreePartial(target)) ||
64				  (!partialMatch && sibling.equalsTree(target)) ) {
65				v.appendElement(sibling);
66			}
67	/*
68			if ( partialMatch ) if ( sibling.equalsTreePartial(target) ) {
69				// subtree rooted at 'sibling' exact or partial equals 'target'
70				v.appendElement(sibling);
71			}
72			if ( !partialMatch ) if ( sibling.equalsTree(target) ) {
73				// subtree rooted at 'sibling' exact or partial equals 'target'
74				v.appendElement(sibling);
75			}
76	*/
77			// regardless of match or not, check any children for matches
78			if ( sibling.getFirstChild()!=null ) {
79				((BaseAST)sibling.getFirstChild()).doWorkForFindAll(v, target, partialMatch);
80			}
81		}		
82	}
83		/** Is node t equal to this in terms of token type and text? */
84		public boolean equals(AST t) {
85			if ( t==null ) return false;
86			return this.getText().equals(t.getText()) &&
87				   this.getType() == t.getType();
88		}
89	/** Is t an exact structural and equals() match of this tree.  The
90	 *  'this' reference is considered the start of a sibling list.
91	 */
92	public boolean equalsList(AST t) {
93		AST sibling;
94	
95		// the empty tree is not a match of any non-null tree.
96		if (t == null) {
97			return false;
98		}
99	
100		// Otherwise, start walking sibling lists.  First mismatch, return false.
101		for (sibling = this; sibling != null && t != null; sibling = sibling.getNextSibling(), t = t.getNextSibling()) {
102			// as a quick optimization, check roots first.
103			if (!sibling.equals(t)) {
104				return false;
105			}
106			// if roots match, do full list match test on children.
107			if (sibling.getFirstChild() != null) {
108				if (!sibling.getFirstChild().equalsList(t.getFirstChild())) {
109					return false;
110				}
111			}
112			// sibling has no kids, make sure t doesn't either
113			else if (t.getFirstChild() != null) {
114				return false;
115			}
116		}
117		if (sibling == null && t == null) {
118			return true;
119		}
120		// one sibling list has more than the other
121		return false;
122	}
123	/** Is 'sub' a subtree of this list?
124	 *  The siblings of the root are NOT ignored.
125	 */
126	public boolean equalsListPartial(AST sub) {
127		AST sibling;
128	
129		// the empty tree is always a subset of any tree.
130		if ( sub==null ) {
131			return true;
132		}
133		
134		// Otherwise, start walking sibling lists.  First mismatch, return false.
135		for (sibling=this;
136			  sibling!=null&&sub!=null;
137			  sibling=sibling.getNextSibling(), sub=sub.getNextSibling())
138		{
139			// as a quick optimization, check roots first.
140			if ( sibling.getType() != sub.getType() ) return false;
141			// if roots match, do partial list match test on children.
142			if ( sibling.getFirstChild()!=null ) {
143				if ( !sibling.getFirstChild().equalsListPartial(sub.getFirstChild()) ) return false;
144			}	
145		}
146		if ( sibling==null && sub!=null ) {
147			// nothing left to match in this tree, but subtree has more
148			return false;
149		}
150		// either both are null or sibling has more, but subtree doesn't	
151		return true;
152	}
153		/** Is tree rooted at 'this' equal to 't'?  The siblings
154		 *  of 'this' are ignored.
155		 */
156		public boolean equalsTree(AST t) {
157			// check roots first.
158			if ( !this.equals(t) ) return false;
159			// if roots match, do full list match test on children.
160			if ( this.getFirstChild()!=null ) {
161				if ( !this.getFirstChild().equalsList(t.getFirstChild()) ) return false;
162			}
163			// sibling has no kids, make sure t doesn't either
164			else if (t.getFirstChild() != null) {
165				return false;
166			}
167			return true;		
168		}
169		/** Is 't' a subtree of the tree rooted at 'this'?  The siblings
170		 *  of 'this' are ignored. 
171		 */
172		public boolean equalsTreePartial(AST sub) {
173			// the empty tree is always a subset of any tree.
174			if ( sub==null ) {
175				return true;
176			}
177		
178			// check roots first.
179			if ( !this.equals(sub) ) return false;
180			// if roots match, do full list partial match test on children.
181			if ( this.getFirstChild()!=null ) {
182				if ( !this.getFirstChild().equalsListPartial(sub.getFirstChild()) ) return false;
183			}
184			return true;		
185		}
186	/** Walk the tree looking for all exact subtree matches.  Return
187	 *  an ASTEnumerator that lets the caller walk the list
188	 *  of subtree roots found herein.
189	 */
190	public ASTEnumeration findAll(AST target) {
191		Vector roots = new Vector(10);
192		AST sibling;
193	
194		// the empty tree cannot result in an enumeration
195		if ( target==null ) {
196			return null;
197		}
198	
199		doWorkForFindAll(roots, target, false);  // find all matches recursively
200	
201		return new ASTEnumerator(roots);
202	}
203	/** Walk the tree looking for all subtrees.  Return
204	 *  an ASTEnumerator that lets the caller walk the list
205	 *  of subtree roots found herein.
206	 */
207	public ASTEnumeration findAllPartial(AST sub) {
208		Vector roots = new Vector(10);
209		AST sibling;
210	
211		// the empty tree cannot result in an enumeration
212		if ( sub==null ) {
213			return null;
214		}
215	
216		doWorkForFindAll(roots, sub, true);  // find all matches recursively
217	
218		return new ASTEnumerator(roots);
219	}
220		/** Get the first child of this node; null if not children */
221		public AST getFirstChild() {
222			return down;
223		}
224		/** Get	the next sibling in line after this one */
225		public AST getNextSibling() {
226			return right;
227		}
228		/** Get the token text for this node */
229		public String getText() { return ""; }
230		/** Get the token type for this node */
231		public int getType() { return 0; }
232		public abstract void initialize(int t, String txt);
233	public abstract void initialize(AST t);
234	public abstract void initialize(Token t);
235		/** Remove all children */
236		public void removeChildren() {
237			down = null;
238		}
239		public void setFirstChild(AST c) {
240			down = (BaseAST)c;
241		}
242		public void setNextSibling(AST n) {
243			right = (BaseAST)n;
244		}
245		/** Set the token text for this node */
246		public void setText(String text) {;}
247		/** Set the token type for this node */
248		public void setType(int ttype) {;}
249		public static void setVerboseStringConversion(boolean verbose, String[] names) {
250			verboseStringConversion = verbose;
251			tokenNames = names;
252		}
253	public String toString() {
254		StringBuffer b = new StringBuffer();
255		// if verbose and type name not same as text (keyword probably)
256		if ( verboseStringConversion &&
257			 !getText().equalsIgnoreCase(tokenNames[getType()]) &&
258			 !getText().equalsIgnoreCase(Tool.stripFrontBack(tokenNames[getType()],"\"","\"")) ) {
259			b.append('[');
260			b.append(getText());
261			b.append(",<");
262			b.append(tokenNames[getType()]);
263			b.append(">]");
264			return b.toString();
265		}
266		return getText();
267	}
268	/** Print out a child-sibling tree in LISP notation */
269	public String toStringList() {
270			AST t = this;
271			String ts="";
272			if ( t.getFirstChild()!=null ) ts+=" (";
273			ts += " "+this.toString();
274			if ( t.getFirstChild()!=null ) {
275					ts += ((BaseAST)t.getFirstChild()).toStringList();
276			}
277			if ( t.getFirstChild()!=null ) ts+=" )";
278			if ( t.getNextSibling()!=null ) {
279					ts += ((BaseAST)t.getNextSibling()).toStringList();
280			}
281			return ts;
282	}
283	public String toStringTree() {
284			AST t = this;
285			String ts="";
286			if ( t.getFirstChild()!=null ) ts+=" (";
287			ts += " "+this.toString();
288			if ( t.getFirstChild()!=null ) {
289					ts += ((BaseAST)t.getFirstChild()).toStringList();
290			}
291			if ( t.getFirstChild()!=null ) ts+=" )";
292			return ts;
293	}
294	}
295