001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2005-2007 Robert Grimm
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.parser;
020:
021: import xtc.tree.Visitor;
022:
023: import xtc.util.Runtime;
024:
025: /**
026: * The parent class of all grammar module visitors. This class
027: * provides a skeleton visitor for processing {@link Grammar grammars}
028: * and self-contained {@link Module modules}, while maintaining a set
029: * of useful flags.
030: *
031: * @author Robert Grimm
032: * @version $Revision: 1.24 $
033: */
034: public abstract class GrammarVisitor extends Visitor {
035:
036: /** The runtime. */
037: protected final Runtime runtime;
038:
039: /** The analyzer utility. */
040: protected final Analyzer analyzer;
041:
042: /**
043: * Flag for whether the current element is the top-level element of
044: * a production.
045: */
046: protected boolean isTopLevel;
047:
048: /** Flag for whether the current element is voided. */
049: protected boolean isVoided;
050:
051: /** Flag for whether the current element is bound. */
052: protected boolean isBound;
053:
054: /**
055: * Flag for whether the current element is the last element of a
056: * sequence.
057: */
058: protected boolean isLastElement;
059:
060: /** Flag for whether the current element is in a predicate. */
061: protected boolean isPredicate;
062:
063: /** Flag for whether the current element is repeated at least once. */
064: protected boolean isRepeatedOnce;
065:
066: /**
067: * Flag for whether the parent element requires that the directly
068: * embedded elements are sequences for {@link CodeGenerator code
069: * generation}. It is used by the {@link Simplifier} to avoid
070: * stripping sequences that need to be restored later on again.
071: */
072: protected boolean needsSequence;
073:
074: /**
075: * Flag for whether to transform ordered choices, repetition, and
076: * options in place, instead of creating a new production. This
077: * flag is used by the {@link Transformer.Lifter lifter} visitor.
078: */
079: protected boolean transformInPlace;
080:
081: /**
082: * Create a new grammar visitor.
083: *
084: * @param runtime The runtime.
085: * @param analyzer The analyzer utility.
086: */
087: public GrammarVisitor(Runtime runtime, Analyzer analyzer) {
088: this .runtime = runtime;
089: this .analyzer = analyzer;
090: }
091:
092: /** Visit the specified grammar. */
093: public Object visit(Grammar g) {
094: // Initialize the per-grammar state.
095: analyzer.register(this );
096: analyzer.init(g);
097:
098: // Process the modules.
099: for (Module m : g.modules) {
100: analyzer.process(m);
101:
102: // Process the module's productions.
103: for (Production p : m.productions)
104: analyzer.process(p);
105: }
106:
107: // Done.
108: return null;
109: }
110:
111: /** Visit the specified self-contained module. */
112: public Object visit(Module m) {
113: // Initialize the per-grammar state.
114: analyzer.register(this );
115: analyzer.init(m);
116:
117: // Process the productioins.
118: for (Production p : m.productions)
119: analyzer.process(p);
120:
121: // Done.
122: return null;
123: }
124:
125: /** Visit the specified production. */
126: public Production visit(Production p) {
127: Object closure = analyzer.enter(p);
128:
129: // Initialize the per-production flags.
130: isTopLevel = true;
131: isVoided = false;
132: isBound = false;
133: isLastElement = false;
134: isPredicate = false;
135: isRepeatedOnce = false;
136: needsSequence = false;
137: transformInPlace = false;
138:
139: p.choice = (OrderedChoice) dispatch(p.choice);
140:
141: analyzer.exit(closure);
142:
143: return p;
144: }
145:
146: /** Visit the specified ordered choice. */
147: public Element visit(OrderedChoice c) {
148: boolean top = isTopLevel;
149: isTopLevel = false;
150: isVoided = false;
151: isBound = false;
152: boolean last = isLastElement;
153: transformInPlace = false;
154:
155: final int length = c.alternatives.size();
156: for (int i = 0; i < length; i++) {
157: isLastElement = top || last;
158: needsSequence = true;
159: c.alternatives.set(i, (Sequence) dispatch(c.alternatives
160: .get(i)));
161: }
162:
163: isLastElement = false;
164: needsSequence = false;
165: return c;
166: }
167:
168: /** Visit the specified repetition. */
169: public Element visit(Repetition r) {
170: isTopLevel = false;
171: isVoided = false;
172: isBound = false;
173: isLastElement = false;
174: boolean rep = isRepeatedOnce;
175: isRepeatedOnce = r.once;
176: needsSequence = false;
177: transformInPlace = false;
178:
179: r.element = (Element) dispatch(r.element);
180:
181: isRepeatedOnce = rep;
182: return r;
183: }
184:
185: /** Visit the specified option. */
186: public Element visit(Option o) {
187: isTopLevel = false;
188: isVoided = false;
189: isBound = false;
190: isLastElement = false;
191: needsSequence = false;
192: transformInPlace = false;
193:
194: o.element = (Element) dispatch(o.element);
195: return o;
196: }
197:
198: /** Visit the specified sequence. */
199: public Element visit(Sequence s) {
200: isTopLevel = false;
201: isVoided = false;
202: isBound = false;
203: boolean last = isLastElement;
204: needsSequence = false;
205:
206: final int size = s.size();
207: for (int i = 0; i < size; i++) {
208: isLastElement = last && (i == size - 1);
209: s.elements.set(i, (Element) dispatch(s.get(i)));
210: }
211:
212: isLastElement = false;
213: return s;
214: }
215:
216: /** Visit the specified predicate. */
217: public Element visit(Predicate p) {
218: isTopLevel = false;
219: isVoided = false;
220: isBound = false;
221: isLastElement = false;
222: boolean seq = needsSequence;
223: needsSequence = true;
224: transformInPlace = false;
225: boolean pred = isPredicate;
226: isPredicate = true;
227:
228: p.element = (Element) dispatch(p.element);
229:
230: isPredicate = pred;
231: needsSequence = seq;
232: return p;
233: }
234:
235: /** Visit the specified semantic predicate. */
236: public Element visit(SemanticPredicate p) {
237: isTopLevel = false;
238: isVoided = false;
239: isBound = false;
240: isLastElement = false;
241: needsSequence = false;
242: transformInPlace = false;
243:
244: p.element = (Element) dispatch(p.element);
245: return p;
246: }
247:
248: /** Visit the specified voided element. */
249: public Element visit(VoidedElement v) {
250: isTopLevel = false;
251: isVoided = true;
252: isBound = false;
253: isLastElement = false;
254: needsSequence = false;
255: transformInPlace = false;
256:
257: v.element = (Element) dispatch(v.element);
258: return v;
259: }
260:
261: /** Visit the specified binding. */
262: public Element visit(Binding b) {
263: isTopLevel = false;
264: isVoided = false;
265: isBound = true;
266: isLastElement = false;
267: needsSequence = false;
268: transformInPlace = false;
269:
270: b.element = (Element) dispatch(b.element);
271: return b;
272: }
273:
274: /** Visit the specified string match. */
275: public Element visit(StringMatch m) {
276: isTopLevel = false;
277: isVoided = false;
278: isBound = true;
279: isLastElement = false;
280: needsSequence = false;
281: transformInPlace = false;
282:
283: m.element = (Element) dispatch(m.element);
284: return m;
285: }
286:
287: /** Visit the specified character case. */
288: public CharCase visit(CharCase c) {
289: isTopLevel = false;
290: isVoided = false;
291: isBound = false;
292: isLastElement = false;
293: needsSequence = false;
294: transformInPlace = false;
295:
296: c.element = (Element) dispatch(c.element);
297: return c;
298: }
299:
300: /** Visit the specified character switch. */
301: public Element visit(CharSwitch s) {
302: isTopLevel = false;
303: isVoided = false;
304: isBound = false;
305: isLastElement = false;
306: needsSequence = false;
307: transformInPlace = false;
308:
309: final int length = s.cases.size();
310: for (int i = 0; i < length; i++) {
311: s.cases.set(i, (CharCase) dispatch(s.cases.get(i)));
312: }
313: s.base = (Element) dispatch(s.base);
314: return s;
315: }
316:
317: /** Visit the specified parser action. */
318: public Element visit(ParserAction pa) {
319: isTopLevel = false;
320: isVoided = false;
321: isBound = false;
322: isLastElement = false;
323: needsSequence = false;
324: transformInPlace = false;
325:
326: pa.element = (Element) dispatch(pa.element);
327: return pa;
328: }
329:
330: /**
331: * Visit the specified element. This method provides the default
332: * implementation for nonterminals, terminals (besides character
333: * switches), node markers, actions, parse tree nodes, null
334: * literals, and value elements.
335: */
336: public Element visit(Element e) {
337: isTopLevel = false;
338: isVoided = false;
339: isBound = false;
340: isLastElement = false;
341: needsSequence = false;
342: transformInPlace = false;
343:
344: return e;
345: }
346:
347: }
|