/*
* Copyright (C) Chaperon. All rights reserved.
* -------------------------------------------------------------------------
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package net.sourceforge.chaperon.build;
import net.sourceforge.chaperon.model.grammar.Grammar;
import net.sourceforge.chaperon.model.symbol.Symbol;
import net.sourceforge.chaperon.model.symbol.SymbolList;
import net.sourceforge.chaperon.model.symbol.SymbolSet;
import org.apache.commons.logging.Log;
/**
* This class creates a collection of FOLLOW sets.
*
* @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
* @version CVS $Id: FollowSetCollection.java,v 1.5 2003/12/09 19:55:53 benedikta Exp $
*/
public class FollowSetCollection
{
private Grammar grammar;
private FirstSetCollection firstsets;
private Symbol[] symbols;
private SymbolSet[] followsets;
private Log log;
private static final EmptyList EMPTYLIST = new EmptyList();
/**
* Create a collection of FOLLOW sets.
*
* @param grammar Grammar.
*/
public FollowSetCollection(Grammar grammar, FirstSetCollection firstsets)
{
this(grammar, firstsets, null);
}
/**
* Create a collection of FOLLOW sets
*
* @param grammar Grammar
* @param log Log, whch should be used.
*/
public FollowSetCollection(Grammar grammar, FirstSetCollection firstsets, Log log)
{
this.grammar = grammar;
this.firstsets = firstsets;
this.log = log;
SymbolSet usedsymbols = grammar.getSymbols();
symbols = new Symbol[usedsymbols.getSymbolCount()];
followsets = new SymbolSet[usedsymbols.getSymbolCount()];
for (int i = 0; i<usedsymbols.getSymbolCount(); i++)
{
if (log!=null)
log.debug("Generating follow set for "+usedsymbols.getSymbol(i).getName());
symbols[i] = usedsymbols.getSymbol(i);
followsets[i] = follow(symbols[i]);
}
}
/**
* Returns the FOLLOW set for a symbol.
*
* @param symbol Symbol.
*
* @return Set of symbols.
*/
public SymbolSet getFollowSet(Symbol symbol)
{
for (int i = 0; i<symbols.length; i++)
if (symbols[i].equals(symbol))
return followsets[i];
throw new IllegalArgumentException("No follow set found for symbol");
}
/**
* Calculates the FOLLOW set. The FOLLOW set is the set of terminal symbols, which come as next
* symbol
*
* @param symbol Symbol.
*
* @return Set of symbol.
*/
private SymbolSet follow(Symbol symbol)
{
System.out.println();
System.out.println("Calculate FOLLOW set for "+symbol);
SymbolSet followset = new SymbolSet();
// if symbol is start symbol, then add symbol for end of file
if (symbol.equals(grammar.getStartSymbol()))
followset.addSymbol(new EndOfFile());
// if production A -> a B b exists, then add every symbol of
// FIRST(b) except the symbol for an empty list to FOLLOW(B)
SymbolList definition;
for (int production = 0; production<grammar.getProductionCount(); production++)
{
definition = grammar.getProduction(production).getDefinition();
for (int position = 0; position<definition.getSymbolCount(); position++)
if (definition.getSymbol(position).equals(symbol))
{
System.out.println("Found "+symbol+" at position "+position+" in production "+production);
SymbolSet firstset = null;
if ((position+1)<definition.getSymbolCount())
{
SymbolList rest = new SymbolList();
for (int restposition = position+1; restposition<definition.getSymbolCount();
restposition++)
rest.addSymbol(definition.getSymbol(restposition));
firstset = firstsets.getFirstSet(rest);
System.out.println("first("+rest+")="+firstset);
followset.addSymbol(firstset);
followset.removeSymbol(EMPTYLIST);
}
if ((position+1)==definition.getSymbolCount())
System.out.println(symbol+" is last symbol of production "+production);
// if a production A -> a B or A -> a B b exist and FIRST(b)
// contains the symbol for an empty list, then every symbol
// of FOLLOW(A) belongs to FOLLOW(B)
if ((((position+1)==definition.getSymbolCount()) || (firstset.contains(EMPTYLIST))) &&
(!grammar.getProduction(production).getSymbol().equals(symbol)))
followset.addSymbol(follow(grammar.getProduction(production).getSymbol()));
}
}
return followset;
}
/**
* Return a string representation of the FOLLOW sets.
*
* @return String representation of the FOLLOW sets.
*/
public String toString()
{
StringBuffer buffer = new StringBuffer();
SymbolSet symbols = grammar.getSymbols();
for (int symbol = 0; symbol<symbols.getSymbolCount(); symbol++)
{
buffer.append("follow(");
buffer.append(symbols.getSymbol(symbol).toString());
buffer.append(")=");
buffer.append(getFollowSet(symbols.getSymbol(symbol)).toString());
buffer.append("\n");
}
return buffer.toString();
}
}
|