/* * xtc - The eXTensible Compiler * Copyright (C) 2006-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 java.util.ArrayList; import java.util.Iterator; import java.util.List; import xtc.tree.Visitor; import xtc.util.Runtime; /** * Visitor to ensure that every alternative has a semantic value. * This visitor assumes that the entire grammar is contained in a * single module and that any automatically deduced semantic values, * including value elements, have been added to the grammar. * * @author Robert Grimm * @version $Revision: 1.12 $ */ public class ValueChecker extends Visitor { /** The runtime. */ protected Runtime runtime; /** The analyzer. */ protected Analyzer analyzer; /** The list of elements. */ protected List<Element> elements; /** * Create a new value checker. * * @param runtime The runtime. * @param analyzer The analyzer. */ public ValueChecker(Runtime runtime, Analyzer analyzer) { this.runtime = runtime; this.analyzer = analyzer; elements = new ArrayList<Element>(); } /** Visit the specified module. */ public void visit(Module m) { // Initialize the per-grammar state. analyzer.register(this); analyzer.init(m); elements.clear(); // Process the productions. for (Production p : m.productions) dispatch(p); } /** Visit the specified full production. */ public void visit(FullProduction p) { dispatch(p.choice); } /** Visit the specified choice. */ public void visit(OrderedChoice c) { for (Sequence alt : c.alternatives) dispatch(alt); } /** Visit the specified sequence. */ public void visit(Sequence s) { // Remember the current number of elements. final int base = elements.size(); // Process the elements of the sequence. for (Iterator<Element> iter = s.elements.iterator(); iter.hasNext(); ) { Element e = iter.next(); if ((! iter.hasNext()) && (e instanceof OrderedChoice)) { // Continue with the trailing choice. dispatch(e); } else { // Add the current element to the list of traversed elements. elements.add(e); } } // Check for a semantic value. if (! s.hasTrailingChoice()) { if (! Analyzer.setsValue(elements, false)) { final int size = elements.size(); if (0 == size) { runtime.error("empty alternative without semantic value", s); } else if (elements.get(size-1).hasLocation()) { runtime.error("last element in alternative without semantic value", elements.get(size-1)); } else { runtime.error("alternative without semantic value", s); } } } // Remove any elements added by processing the sequence. if (0 == base) { elements.clear(); } else { elements.subList(base, elements.size()).clear(); } } }