/*
* 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.common.IntegerList;
import net.sourceforge.chaperon.model.grammar.Grammar;
import net.sourceforge.chaperon.model.symbol.SymbolSet;
import org.apache.commons.logging.Log;
import java.util.ArrayList;
/**
* This class contains a collection of item sets.
*
* @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
* @version CVS $Id: ItemSetCollection.java,v 1.15 2003/12/09 19:55:52 benedikta Exp $
*/
public class ItemSetCollection
{
private static final EndOfFile EOF = new EndOfFile();
private static final int NOTCHANGED = 0;
private static final int CHANGED = 1;
private ArrayList itemsets = new ArrayList();
private Grammar grammar;
private FirstSetCollection firstsets;
private SymbolSet tsymbols;
private SymbolSet ntsymbols;
private Log log;
/**
* Create a new collection of item sets, calculated with the aid of the grammar. The constructor
* calculates all state and transitions and combine all itemsets with the same core.
*
* @param grammar Grammar.
* @param firstsets First sets.
*/
public ItemSetCollection(Grammar grammar, FirstSetCollection firstsets)
{
this(grammar, firstsets, null);
}
/**
* Create a new collection of item sets, calculated with the aid of the grammar. The constructor
* calculates all state and transitions and combine all itemsets with the same core.
*
* @param grammar Grammar
* @param firstsets First sets.
* @param log Log, which should be used.
*/
public ItemSetCollection(Grammar grammar, FirstSetCollection firstsets, Log log)
{
this.grammar = grammar;
this.firstsets = firstsets;
this.log = log;
SymbolSet symbols = grammar.getSymbols();
tsymbols = symbols.getTerminals();
ntsymbols = symbols.getNonterminals();
// C = closure( [S'=^S,EOF] )
IntegerList changedState = new IntegerList(); // 0=not changed 1=changed
addItemSet(getStartItemSet());
changedState.add(CHANGED);
boolean mustrepeat = false;
for (int i = 0; i<getItemSetCount(); i++)
{
changedState.set(i, NOTCHANGED);
ItemSet I = getItemSet(i);
// J = goto(I,X) add to C, for all nonterminal and terminal symbols X
// for the non terminal symbols
SymbolSet nextnonterminals = I.getNextNonterminals();
for (int j = 0; j<nextnonterminals.getSymbolCount(); j++)
{
ItemSet J = I.jump(nextnonterminals.getSymbol(j));
if (!J.isEmpty())
{
int index = indexOfCore(J);
if (index<0) // if C doesn't contain J
{
index = addItemSet(J);
changedState.add(CHANGED);
}
else // otherwise the found state extends through J
{
if (getItemSet(index).addItemSet(J)) // if the found state change
{
if (index<changedState.getCount())
changedState.set(index, CHANGED);
else
changedState.add(CHANGED);
if (index<=i) // if J before I, and J
// was changed then must the loop repeat
mustrepeat = true;
}
}
I.setTransition(nextnonterminals.getSymbol(j), index); // stores the transition for this symbol
}
}
// and for the terminal symbols
SymbolSet nextterminals = I.getNextTerminals();
for (int j = 0; j<nextterminals.getSymbolCount(); j++)
{
ItemSet J = I.jump(nextterminals.getSymbol(j));
if (!J.isEmpty())
{
int index = indexOfCore(J);
if (index<0) // if C doesn't contain J
{
index = addItemSet(J);
changedState.add(CHANGED);
}
else // otherwise the found state extends through J
{
if (getItemSet(index).addItemSet(J)) // if the found state change
{
if (index<changedState.getCount())
changedState.set(index, CHANGED);
else
changedState.add(CHANGED);
if (index<=i) // if J before I, and J
// was changed then must the loop repeat
mustrepeat = true;
}
}
I.setTransition(nextterminals.getSymbol(j), index); // stores the transition for this symbol
}
}
}
do
{
mustrepeat = false;
for (int i = 0; i<getItemSetCount(); i++)
if (changedState.get(i)==CHANGED)
{
changedState.set(i, NOTCHANGED);
ItemSet I = getItemSet(i);
symbols = I.getShiftSymbols();
for (int j = 0; j<symbols.getSymbolCount(); j++)
{
ItemSet J = I.jump(symbols.getSymbol(j));
int index = I.getTransition(symbols.getSymbol(j));
if (getItemSet(index).addItemSet(J)) // if the found state change
{
if (index<changedState.getCount())
changedState.set(index, CHANGED);
else
changedState.add(CHANGED);
if (index<=i) // if J before I, and J
// was changed then must the loop repeat
mustrepeat = true;
}
}
}
}
while (mustrepeat); // Repeat till no state changed
}
/**
* Return the item set as start point for the calculation.
*
* @return Start point for the calculation.
*/
private ItemSet getStartItemSet()
{
ItemSet I = new ItemSet(grammar, firstsets);
IntegerList startlist = grammar.getProductionList(grammar.getStartSymbol());
for (int i = 0; i<startlist.getCount(); i++)
I.addItem(startlist.get(i), 0, EOF);
return I.closure();
}
/**
* Add a itemset to this collection.
*
* @param itemset Itemset.
*
* @return Index of the itemset in the collection.
*/
public int addItemSet(ItemSet itemset)
{
int index = indexOf(itemset);
if (index==-1)
{
itemsets.add(itemset);
index = itemsets.size()-1;
}
return index;
}
/**
* Return an item set given by an index.
*
* @param index Index of the itemset.
*
* @return Itemset.
*/
public ItemSet getItemSet(int index)
{
return (ItemSet)itemsets.get(index);
}
/**
* Return the count of item sets in this collection
*
* @return Count of itemsets.
*/
public int getItemSetCount()
{
return itemsets.size();
}
/**
* Return the index of an item set. If the collection does not contain the itemset, then return
* this method will return -1.
*
* @param itemset Itemset, which should be found.
*
* @return Index of the itemset.
*/
public int indexOf(ItemSet itemset)
{
for (int i = 0; i<itemsets.size(); i++)
if (((ItemSet)itemsets.get(i)).equals(itemset))
return i;
return -1;
}
/**
* If this collection contains the item set.
*
* @param itemset Itemset, which should be found.
*
* @return True, if the collection contains the itemset.
*/
public boolean contains(ItemSet itemset)
{
for (int i = 0; i<itemsets.size(); i++)
if (((ItemSet)itemsets.get(i)).equals(itemset))
return true;
return false;
}
/**
* Return the index of an item set. If the collection does not contain the itemset, then this
* method will return -1. This Method compare only the core from the item sets.
*
* @param itemset Itemset, which should be found.
*
* @return Index of the Itemset
*/
public int indexOfCore(ItemSet itemset)
{
for (int i = 0; i<itemsets.size(); i++)
if (((ItemSet)itemsets.get(i)).equalsCore(itemset))
return i;
return -1;
}
/**
* If this collection contains the item set. This method compares only the core of the itemset.
*
* @param itemset Itemset, which should be found.
*
* @return True, if the collection contain the itemset.
*/
public boolean containsCore(ItemSet itemset)
{
for (int i = 0; i<itemsets.size(); i++)
if (((ItemSet)itemsets.get(i)).equalsCore(itemset))
return true;
return false;
}
/**
* Return a string representation of the collection.
*
* @return String representation of the collection.
*/
public String toString()
{
StringBuffer buffer = new StringBuffer();
for (int i = 0; i<getItemSetCount(); i++)
{
buffer.append("State ");
buffer.append(String.valueOf(i));
buffer.append(":\n");
buffer.append(getItemSet(i).toString());
buffer.append("\n");
}
return buffer.toString();
}
}