/*
* 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.parser.generator;
import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.logger.Logger;
import net.sourceforge.chaperon.grammar.Grammar;
import net.sourceforge.chaperon.grammar.symbol.EmptySymbol;
import net.sourceforge.chaperon.grammar.symbol.Symbol;
import net.sourceforge.chaperon.grammar.symbol.SymbolList;
import net.sourceforge.chaperon.helpers.IntegerList;
/**
* This class creates the set of first-sets
*
* @author Stephan Michels
* @version CVS $Id: FirstSets.java,v 1.6 2002/05/06 16:22:57 benedikta Exp $
*/
public class FirstSets implements LogEnabled
{
private Grammar _grammar;
private Symbol[] _symbols;
private SymbolList[] _firstsets;
private Logger _logger;
/**
* Create a firstset of the first sets
*
* @param grammar Grammar
* @param logger the logger
*/
public FirstSets(Grammar grammar, Logger logger)
{
_grammar = grammar;
enableLogging(logger);
SymbolList usedsymbols = grammar.getSymbols();
_symbols = new Symbol[usedsymbols.getSymbolCount()];
_firstsets = new SymbolList[usedsymbols.getSymbolCount()];
for (int i = 0; i < usedsymbols.getSymbolCount(); i++)
{
if (_logger!=null)
_logger.debug("Generating first set for "+usedsymbols.getSymbol(i).getName());
_symbols[i] = usedsymbols.getSymbol(i);
_firstsets[i] = first(_symbols[i]);
}
}
/**
* Returns the first set for a symbol
*
* @param symbol Symbol
*
* @return List of symbols
*/
public SymbolList getFirstSet(Symbol symbol)
{
for (int i = 0; i < _symbols.length; i++)
if (_symbols[i].equals(symbol))
return _firstsets[i];
return new SymbolList();
}
/**
* Provide component with a logger.
*
* @param logger the logger
*/
public void enableLogging(Logger logger)
{
_logger = logger;
}
/**
* Calculates the FIRST set. The FIRST set is the set of
* terminal symbols, which come as next symbol
*
* @param symbol Symbol
*
* @return List of symbol
*/
private SymbolList first(Symbol symbol)
{
return first(symbol, new SymbolList(true));
}
/**
* Calculates the FIRST set. The FIRST set is the set of
* terminal symbols, which come as next symbol
*
* @param symbol Symbol
*
* @return List of symbol
*/
private SymbolList first(Symbol symbol, SymbolList visited)
{
SymbolList firstset = new SymbolList(true);
// if the symbol is a terminal symbol
if (symbol.isTerminal())
{
firstset.addSymbol(symbol);
return firstset;
}
if (visited.contains(symbol))
return firstset;
else
visited.addSymbol(symbol);
//System.out.println("Symbol="+symbol.toString());
// if is a non terminal symbol
IntegerList productions = _grammar.getProductionList().getProductionList(symbol);
SymbolList examined = new SymbolList(true); // List of all examined symbols
SymbolList productiondefinition, newfirstset;
boolean foundEMPTY;
int i, j, k; // index variables
Symbol newsymbol;
for (i = 0; i < productions.getSize(); i++)
{
productiondefinition = _grammar.getProductionList().getProduction(
productions.get(i)).getDefinition();
if (productiondefinition.getSymbolCount() == 0)
{
// Symbol for a empty firstset added
firstset.addSymbol(EmptySymbol.EMPTY);
}
else
{
// for every symbol in the production
j = 0;
do
{
foundEMPTY = true;
newsymbol = productiondefinition.getSymbol(j);
if (newsymbol.isTerminal())
{
// if a terminal symbol
firstset.addSymbol(newsymbol);
}
else if (!newsymbol.equals(symbol))
{
// and if a non terminal symbol
if (!examined.contains(newsymbol))
{
newfirstset = first(newsymbol, visited);
foundEMPTY = newfirstset.contains(EmptySymbol.EMPTY);
for (k = 0; k < newfirstset.getSymbolCount(); k++)
if (!newfirstset.getSymbol(k).isEmpty())
firstset.addSymbol(newfirstset.getSymbol(k));
examined.addSymbol(newsymbol);
}
}
j++;
}
while ((!newsymbol.isTerminal()) && (foundEMPTY) &&
(j < productiondefinition.getSymbolCount()) &&
(!productiondefinition.getSymbol(j - 1).equals(symbol)));
}
}
//System.out.println("Symbol="+symbol.toString()+" beendet");
return firstset;
}
}