/*
* xtc - The eXTensible Compiler
* Copyright (C) 2005-2007 Robert Grimm
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package xtc.parser;
import xtc.tree.Visitor;
import xtc.util.Runtime;
/**
* The parent class of all grammar module visitors. This class
* provides a skeleton visitor for processing {@link Grammar grammars}
* and self-contained {@link Module modules}, while maintaining a set
* of useful flags.
*
* @author Robert Grimm
* @version $Revision: 1.24 $
*/
public abstract class GrammarVisitor extends Visitor {
/** The runtime. */
protected final Runtime runtime;
/** The analyzer utility. */
protected final Analyzer analyzer;
/**
* Flag for whether the current element is the top-level element of
* a production.
*/
protected boolean isTopLevel;
/** Flag for whether the current element is voided. */
protected boolean isVoided;
/** Flag for whether the current element is bound. */
protected boolean isBound;
/**
* Flag for whether the current element is the last element of a
* sequence.
*/
protected boolean isLastElement;
/** Flag for whether the current element is in a predicate. */
protected boolean isPredicate;
/** Flag for whether the current element is repeated at least once. */
protected boolean isRepeatedOnce;
/**
* Flag for whether the parent element requires that the directly
* embedded elements are sequences for {@link CodeGenerator code
* generation}. It is used by the {@link Simplifier} to avoid
* stripping sequences that need to be restored later on again.
*/
protected boolean needsSequence;
/**
* Flag for whether to transform ordered choices, repetition, and
* options in place, instead of creating a new production. This
* flag is used by the {@link Transformer.Lifter lifter} visitor.
*/
protected boolean transformInPlace;
/**
* Create a new grammar visitor.
*
* @param runtime The runtime.
* @param analyzer The analyzer utility.
*/
public GrammarVisitor(Runtime runtime, Analyzer analyzer) {
this.runtime = runtime;
this.analyzer = analyzer;
}
/** Visit the specified grammar. */
public Object visit(Grammar g) {
// Initialize the per-grammar state.
analyzer.register(this);
analyzer.init(g);
// Process the modules.
for (Module m : g.modules) {
analyzer.process(m);
// Process the module's productions.
for (Production p : m.productions) analyzer.process(p);
}
// Done.
return null;
}
/** Visit the specified self-contained module. */
public Object visit(Module m) {
// Initialize the per-grammar state.
analyzer.register(this);
analyzer.init(m);
// Process the productioins.
for (Production p : m.productions) analyzer.process(p);
// Done.
return null;
}
/** Visit the specified production. */
public Production visit(Production p) {
Object closure = analyzer.enter(p);
// Initialize the per-production flags.
isTopLevel = true;
isVoided = false;
isBound = false;
isLastElement = false;
isPredicate = false;
isRepeatedOnce = false;
needsSequence = false;
transformInPlace = false;
p.choice = (OrderedChoice)dispatch(p.choice);
analyzer.exit(closure);
return p;
}
/** Visit the specified ordered choice. */
public Element visit(OrderedChoice c) {
boolean top = isTopLevel;
isTopLevel = false;
isVoided = false;
isBound = false;
boolean last = isLastElement;
transformInPlace = false;
final int length = c.alternatives.size();
for (int i=0; i<length; i++) {
isLastElement = top || last;
needsSequence = true;
c.alternatives.set(i, (Sequence)dispatch(c.alternatives.get(i)));
}
isLastElement = false;
needsSequence = false;
return c;
}
/** Visit the specified repetition. */
public Element visit(Repetition r) {
isTopLevel = false;
isVoided = false;
isBound = false;
isLastElement = false;
boolean rep = isRepeatedOnce;
isRepeatedOnce = r.once;
needsSequence = false;
transformInPlace = false;
r.element = (Element)dispatch(r.element);
isRepeatedOnce = rep;
return r;
}
/** Visit the specified option. */
public Element visit(Option o) {
isTopLevel = false;
isVoided = false;
isBound = false;
isLastElement = false;
needsSequence = false;
transformInPlace = false;
o.element = (Element)dispatch(o.element);
return o;
}
/** Visit the specified sequence. */
public Element visit(Sequence s) {
isTopLevel = false;
isVoided = false;
isBound = false;
boolean last = isLastElement;
needsSequence = false;
final int size = s.size();
for (int i=0; i<size; i++) {
isLastElement = last && (i == size-1);
s.elements.set(i, (Element)dispatch(s.get(i)));
}
isLastElement = false;
return s;
}
/** Visit the specified predicate. */
public Element visit(Predicate p) {
isTopLevel = false;
isVoided = false;
isBound = false;
isLastElement = false;
boolean seq = needsSequence;
needsSequence = true;
transformInPlace = false;
boolean pred = isPredicate;
isPredicate = true;
p.element = (Element)dispatch(p.element);
isPredicate = pred;
needsSequence = seq;
return p;
}
/** Visit the specified semantic predicate. */
public Element visit(SemanticPredicate p) {
isTopLevel = false;
isVoided = false;
isBound = false;
isLastElement = false;
needsSequence = false;
transformInPlace = false;
p.element = (Element)dispatch(p.element);
return p;
}
/** Visit the specified voided element. */
public Element visit(VoidedElement v) {
isTopLevel = false;
isVoided = true;
isBound = false;
isLastElement = false;
needsSequence = false;
transformInPlace = false;
v.element = (Element)dispatch(v.element);
return v;
}
/** Visit the specified binding. */
public Element visit(Binding b) {
isTopLevel = false;
isVoided = false;
isBound = true;
isLastElement = false;
needsSequence = false;
transformInPlace = false;
b.element = (Element)dispatch(b.element);
return b;
}
/** Visit the specified string match. */
public Element visit(StringMatch m) {
isTopLevel = false;
isVoided = false;
isBound = true;
isLastElement = false;
needsSequence = false;
transformInPlace = false;
m.element = (Element)dispatch(m.element);
return m;
}
/** Visit the specified character case. */
public CharCase visit(CharCase c) {
isTopLevel = false;
isVoided = false;
isBound = false;
isLastElement = false;
needsSequence = false;
transformInPlace = false;
c.element = (Element)dispatch(c.element);
return c;
}
/** Visit the specified character switch. */
public Element visit(CharSwitch s) {
isTopLevel = false;
isVoided = false;
isBound = false;
isLastElement = false;
needsSequence = false;
transformInPlace = false;
final int length = s.cases.size();
for (int i=0; i<length; i++) {
s.cases.set(i, (CharCase)dispatch(s.cases.get(i)));
}
s.base = (Element)dispatch(s.base);
return s;
}
/** Visit the specified parser action. */
public Element visit(ParserAction pa) {
isTopLevel = false;
isVoided = false;
isBound = false;
isLastElement = false;
needsSequence = false;
transformInPlace = false;
pa.element = (Element)dispatch(pa.element);
return pa;
}
/**
* Visit the specified element. This method provides the default
* implementation for nonterminals, terminals (besides character
* switches), node markers, actions, parse tree nodes, null
* literals, and value elements.
*/
public Element visit(Element e) {
isTopLevel = false;
isVoided = false;
isBound = false;
isLastElement = false;
needsSequence = false;
transformInPlace = false;
return e;
}
}