]>
Commit | Line | Data |
---|---|---|
427c49bc A |
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: //depot/code/org.antlr/release/antlr-2.7.7/lib/cpp/src/BaseAST.cpp#2 $ | |
6 | */ | |
7 | ||
8 | #include "antlr/config.hpp" | |
9 | ||
10 | //#include <iostream> | |
11 | ||
12 | #include "antlr/AST.hpp" | |
13 | #include "antlr/BaseAST.hpp" | |
14 | ||
15 | ANTLR_USING_NAMESPACE(std) | |
16 | #ifdef ANTLR_CXX_SUPPORTS_NAMESPACE | |
17 | namespace antlr { | |
18 | #endif | |
19 | ||
20 | size_t BaseAST::getNumberOfChildren() const | |
21 | { | |
22 | RefBaseAST t = this->down; | |
23 | size_t n = 0; | |
24 | if( t ) | |
25 | { | |
26 | n = 1; | |
27 | while( t->right ) | |
28 | { | |
29 | t = t->right; | |
30 | n++; | |
31 | } | |
32 | return n; | |
33 | } | |
34 | return n; | |
35 | } | |
36 | ||
37 | void BaseAST::doWorkForFindAll( | |
38 | ANTLR_USE_NAMESPACE(std)vector<RefAST>& v, | |
39 | RefAST target,bool partialMatch) | |
40 | { | |
41 | // Start walking sibling lists, looking for matches. | |
42 | for (RefAST sibling=this; | |
43 | sibling; | |
44 | sibling=sibling->getNextSibling()) | |
45 | { | |
46 | if ( (partialMatch && sibling->equalsTreePartial(target)) || | |
47 | (!partialMatch && sibling->equalsTree(target)) ) { | |
48 | v.push_back(sibling); | |
49 | } | |
50 | // regardless of match or not, check any children for matches | |
51 | if ( sibling->getFirstChild() ) { | |
52 | RefBaseAST(sibling->getFirstChild())->doWorkForFindAll(v, target, partialMatch); | |
53 | } | |
54 | } | |
55 | } | |
56 | ||
57 | /** Is t an exact structural and equals() match of this tree. The | |
58 | * 'this' reference is considered the start of a sibling list. | |
59 | */ | |
60 | bool BaseAST::equalsList(RefAST t) const | |
61 | { | |
62 | // the empty tree is not a match of any non-null tree. | |
63 | if (!t) | |
64 | return false; | |
65 | ||
66 | // Otherwise, start walking sibling lists. First mismatch, return false. | |
67 | RefAST sibling=this; | |
68 | for (;sibling && t; | |
69 | sibling=sibling->getNextSibling(), t=t->getNextSibling()) { | |
70 | // as a quick optimization, check roots first. | |
71 | if (!sibling->equals(t)) | |
72 | return false; | |
73 | // if roots match, do full list match test on children. | |
74 | if (sibling->getFirstChild()) { | |
75 | if (!sibling->getFirstChild()->equalsList(t->getFirstChild())) | |
76 | return false; | |
77 | } | |
78 | // sibling has no kids, make sure t doesn't either | |
79 | else if (t->getFirstChild()) | |
80 | return false; | |
81 | } | |
82 | ||
83 | if (!sibling && !t) | |
84 | return true; | |
85 | ||
86 | // one sibling list has more than the other | |
87 | return false; | |
88 | } | |
89 | ||
90 | /** Is 'sub' a subtree of this list? | |
91 | * The siblings of the root are NOT ignored. | |
92 | */ | |
93 | bool BaseAST::equalsListPartial(RefAST sub) const | |
94 | { | |
95 | // the empty tree is always a subset of any tree. | |
96 | if (!sub) | |
97 | return true; | |
98 | ||
99 | // Otherwise, start walking sibling lists. First mismatch, return false. | |
100 | RefAST sibling=this; | |
101 | for (;sibling && sub; | |
102 | sibling=sibling->getNextSibling(), sub=sub->getNextSibling()) { | |
103 | // as a quick optimization, check roots first. | |
104 | if (!sibling->equals(sub)) | |
105 | return false; | |
106 | // if roots match, do partial list match test on children. | |
107 | if (sibling->getFirstChild()) | |
108 | if (!sibling->getFirstChild()->equalsListPartial(sub->getFirstChild())) | |
109 | return false; | |
110 | } | |
111 | ||
112 | if (!sibling && sub) | |
113 | // nothing left to match in this tree, but subtree has more | |
114 | return false; | |
115 | ||
116 | // either both are null or sibling has more, but subtree doesn't | |
117 | return true; | |
118 | } | |
119 | ||
120 | /** Is tree rooted at 'this' equal to 't'? The siblings | |
121 | * of 'this' are ignored. | |
122 | */ | |
123 | bool BaseAST::equalsTree(RefAST t) const | |
124 | { | |
125 | // check roots first | |
126 | if (!equals(t)) | |
127 | return false; | |
128 | // if roots match, do full list match test on children. | |
129 | if (getFirstChild()) { | |
130 | if (!getFirstChild()->equalsList(t->getFirstChild())) | |
131 | return false; | |
132 | } | |
133 | // sibling has no kids, make sure t doesn't either | |
134 | else if (t->getFirstChild()) | |
135 | return false; | |
136 | ||
137 | return true; | |
138 | } | |
139 | ||
140 | /** Is 'sub' a subtree of the tree rooted at 'this'? The siblings | |
141 | * of 'this' are ignored. | |
142 | */ | |
143 | bool BaseAST::equalsTreePartial(RefAST sub) const | |
144 | { | |
145 | // the empty tree is always a subset of any tree. | |
146 | if (!sub) | |
147 | return true; | |
148 | ||
149 | // check roots first | |
150 | if (!equals(sub)) | |
151 | return false; | |
152 | // if roots match, do full list partial match test on children. | |
153 | if (getFirstChild()) | |
154 | if (!getFirstChild()->equalsListPartial(sub->getFirstChild())) | |
155 | return false; | |
156 | ||
157 | return true; | |
158 | } | |
159 | ||
160 | /** Walk the tree looking for all exact subtree matches. Return | |
161 | * an ASTEnumerator that lets the caller walk the list | |
162 | * of subtree roots found herein. | |
163 | */ | |
164 | ANTLR_USE_NAMESPACE(std)vector<RefAST> BaseAST::findAll(RefAST target) | |
165 | { | |
166 | ANTLR_USE_NAMESPACE(std)vector<RefAST> roots; | |
167 | ||
168 | // the empty tree cannot result in an enumeration | |
169 | if (target) { | |
170 | doWorkForFindAll(roots,target,false); // find all matches recursively | |
171 | } | |
172 | ||
173 | return roots; | |
174 | } | |
175 | ||
176 | /** Walk the tree looking for all subtrees. Return | |
177 | * an ASTEnumerator that lets the caller walk the list | |
178 | * of subtree roots found herein. | |
179 | */ | |
180 | ANTLR_USE_NAMESPACE(std)vector<RefAST> BaseAST::findAllPartial(RefAST target) | |
181 | { | |
182 | ANTLR_USE_NAMESPACE(std)vector<RefAST> roots; | |
183 | ||
184 | // the empty tree cannot result in an enumeration | |
185 | if (target) | |
186 | doWorkForFindAll(roots,target,true); // find all matches recursively | |
187 | ||
188 | return roots; | |
189 | } | |
190 | ||
191 | ANTLR_USE_NAMESPACE(std)string BaseAST::toStringList() const | |
192 | { | |
193 | ANTLR_USE_NAMESPACE(std)string ts=""; | |
194 | ||
195 | if (getFirstChild()) | |
196 | { | |
197 | ts+=" ( "; | |
198 | ts+=toString(); | |
199 | ts+=getFirstChild()->toStringList(); | |
200 | ts+=" )"; | |
201 | } | |
202 | else | |
203 | { | |
204 | ts+=" "; | |
205 | ts+=toString(); | |
206 | } | |
207 | ||
208 | if (getNextSibling()) | |
209 | ts+=getNextSibling()->toStringList(); | |
210 | ||
211 | return ts; | |
212 | } | |
213 | ||
214 | ANTLR_USE_NAMESPACE(std)string BaseAST::toStringTree() const | |
215 | { | |
216 | ANTLR_USE_NAMESPACE(std)string ts = ""; | |
217 | ||
218 | if (getFirstChild()) | |
219 | { | |
220 | ts+=" ( "; | |
221 | ts+=toString(); | |
222 | ts+=getFirstChild()->toStringList(); | |
223 | ts+=" )"; | |
224 | } | |
225 | else | |
226 | { | |
227 | ts+=" "; | |
228 | ts+=toString(); | |
229 | } | |
230 | return ts; | |
231 | } | |
232 | ||
233 | #ifdef ANTLR_SUPPORT_XML | |
234 | /* This whole XML output stuff needs a little bit more thought | |
235 | * I'd like to store extra XML data in the node. e.g. for custom ast's | |
236 | * with for instance symboltable references. This | |
237 | * should be more pluggable.. | |
238 | * @returns boolean value indicating wether a closetag should be produced. | |
239 | */ | |
240 | bool BaseAST::attributesToStream( ANTLR_USE_NAMESPACE(std)ostream& out ) const | |
241 | { | |
242 | out << "text=\"" << this->getText() | |
243 | << "\" type=\"" << this->getType() << "\""; | |
244 | ||
245 | return false; | |
246 | } | |
247 | ||
248 | void BaseAST::toStream( ANTLR_USE_NAMESPACE(std)ostream& out ) const | |
249 | { | |
250 | for( RefAST node = this; node != 0; node = node->getNextSibling() ) | |
251 | { | |
252 | out << "<" << this->typeName() << " "; | |
253 | ||
254 | // Write out attributes and if there is extra data... | |
255 | bool need_close_tag = node->attributesToStream( out ); | |
256 | ||
257 | if( need_close_tag ) | |
258 | { | |
259 | // got children so write them... | |
260 | if( node->getFirstChild() != 0 ) | |
261 | node->getFirstChild()->toStream( out ); | |
262 | ||
263 | // and a closing tag.. | |
264 | out << "</" << node->typeName() << ">" << endl; | |
265 | } | |
266 | } | |
267 | } | |
268 | #endif | |
269 | ||
270 | // this is nasty, but it makes the code generation easier | |
271 | ANTLR_API RefAST nullAST; | |
272 | ||
273 | #if defined(_MSC_VER) && !defined(__ICL) // Microsoft Visual C++ | |
274 | extern ANTLR_API AST* const nullASTptr = 0; | |
275 | #else | |
276 | ANTLR_API AST* const nullASTptr = 0; | |
277 | #endif | |
278 | ||
279 | #ifdef ANTLR_CXX_SUPPORTS_NAMESPACE | |
280 | } | |
281 | #endif |