001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2006-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 java.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import xtc.tree.Visitor;
026:
027: import xtc.util.Runtime;
028:
029: /**
030: * Visitor to ensure that every alternative has a semantic value.
031: * This visitor assumes that the entire grammar is contained in a
032: * single module and that any automatically deduced semantic values,
033: * including value elements, have been added to the grammar.
034: *
035: * @author Robert Grimm
036: * @version $Revision: 1.12 $
037: */
038: public class ValueChecker extends Visitor {
039:
040: /** The runtime. */
041: protected Runtime runtime;
042:
043: /** The analyzer. */
044: protected Analyzer analyzer;
045:
046: /** The list of elements. */
047: protected List<Element> elements;
048:
049: /**
050: * Create a new value checker.
051: *
052: * @param runtime The runtime.
053: * @param analyzer The analyzer.
054: */
055: public ValueChecker(Runtime runtime, Analyzer analyzer) {
056: this .runtime = runtime;
057: this .analyzer = analyzer;
058: elements = new ArrayList<Element>();
059: }
060:
061: /** Visit the specified module. */
062: public void visit(Module m) {
063: // Initialize the per-grammar state.
064: analyzer.register(this );
065: analyzer.init(m);
066: elements.clear();
067:
068: // Process the productions.
069: for (Production p : m.productions)
070: dispatch(p);
071: }
072:
073: /** Visit the specified full production. */
074: public void visit(FullProduction p) {
075: dispatch(p.choice);
076: }
077:
078: /** Visit the specified choice. */
079: public void visit(OrderedChoice c) {
080: for (Sequence alt : c.alternatives)
081: dispatch(alt);
082: }
083:
084: /** Visit the specified sequence. */
085: public void visit(Sequence s) {
086: // Remember the current number of elements.
087: final int base = elements.size();
088:
089: // Process the elements of the sequence.
090: for (Iterator<Element> iter = s.elements.iterator(); iter
091: .hasNext();) {
092: Element e = iter.next();
093:
094: if ((!iter.hasNext()) && (e instanceof OrderedChoice)) {
095: // Continue with the trailing choice.
096: dispatch(e);
097: } else {
098: // Add the current element to the list of traversed elements.
099: elements.add(e);
100: }
101: }
102:
103: // Check for a semantic value.
104: if (!s.hasTrailingChoice()) {
105: if (!Analyzer.setsValue(elements, false)) {
106: final int size = elements.size();
107:
108: if (0 == size) {
109: runtime.error(
110: "empty alternative without semantic value",
111: s);
112: } else if (elements.get(size - 1).hasLocation()) {
113: runtime
114: .error(
115: "last element in alternative without semantic value",
116: elements.get(size - 1));
117: } else {
118: runtime.error("alternative without semantic value",
119: s);
120: }
121: }
122: }
123:
124: // Remove any elements added by processing the sequence.
125: if (0 == base) {
126: elements.clear();
127: } else {
128: elements.subList(base, elements.size()).clear();
129: }
130: }
131:
132: }
|