001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 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: * Visitor to ensure that every alternative is reachable.
027: *
028: * @author Robert Grimm
029: * @version $Revision: 1.2 $
030: */
031: public class ReachabilityChecker extends Visitor {
032:
033: /** The runtime. */
034: protected Runtime runtime;
035:
036: /** The analyzer. */
037: protected Analyzer analyzer;
038:
039: /**
040: * Create a new reachability checker.
041: *
042: * @param runtime The runtime.
043: * @param analyzer The analyzer.
044: */
045: public ReachabilityChecker(Runtime runtime, Analyzer analyzer) {
046: this .runtime = runtime;
047: this .analyzer = analyzer;
048: }
049:
050: /** Visit the specified grammar. */
051: public void visit(Grammar g) {
052: // Initialize the per-grammar state.
053: analyzer.register(this );
054: analyzer.init(g);
055:
056: // Process the modules and productions.
057: for (Module m : g.modules) {
058: analyzer.process(m);
059: for (Production p : m.productions) {
060: if (p.isFull()) {
061: analyzer.process(p);
062: }
063: }
064: }
065: }
066:
067: /** Visit the specified module. */
068: public void visit(Module m) {
069: // Initialize the per-grammar state.
070: analyzer.register(this );
071: analyzer.init(m);
072:
073: // Process the productions.
074: for (Production p : m.productions)
075: analyzer.process(p);
076: }
077:
078: /** Visit the specified full production. */
079: public void visit(FullProduction p) {
080: dispatch(p.choice);
081: }
082:
083: /** Visit the specified choice. */
084: public void visit(OrderedChoice c) {
085: final int size = c.alternatives.size();
086: for (int i = 0; i < size; i++) {
087: Sequence s = c.alternatives.get(i);
088: if (analyzer.matchesEmpty(s) && (i < size - 1)) {
089: runtime.error("unreachable alternative", c.alternatives
090: .get(i + 1));
091: break;
092: } else {
093: dispatch(s);
094: }
095: }
096: }
097:
098: /** Visit the specified sequence. */
099: public void visit(Sequence s) {
100: for (Element e : s.elements)
101: dispatch(e);
102: }
103:
104: /** Visit the specified unary operator. */
105: public void visit(UnaryOperator op) {
106: dispatch(op.element);
107: }
108:
109: /** Visit the specified element. */
110: public void visit(Element e) {
111: // Nothing to do.
112: }
113:
114: }
|