/*
* 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.grammar.Production;
import net.sourceforge.chaperon.model.symbol.Nonterminal;
import net.sourceforge.chaperon.model.symbol.Symbol;
import net.sourceforge.chaperon.model.symbol.SymbolList;
import net.sourceforge.chaperon.model.symbol.SymbolSet;
import net.sourceforge.chaperon.model.symbol.Terminal;
/**
* This class represents a set of items, which means positions of production, in production. These
* states were used to decribes states.
*
* @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
* @version CVS $Id: State.java,v 1.8 2003/12/09 19:55:53 benedikta Exp $
*/
public class State
{
private Production[] productions = new Production[0];
private int[] positions = new int[0];
// The symbols, which translate the states into other states
private ShiftAction[] shiftactions = new ShiftAction[0];
private ReduceAction[] reduceactions = new ReduceAction[0];
private Grammar grammar;
private static final EmptyList EMPTYLIST = new EmptyList();
/**
* Create an empty set of items.
*
* @param grammar Grammar.
*/
public State(Grammar grammar)
{
this.grammar = grammar;
}
/**
* Add a item to this set.
*
* @param production Production.
* @param position Position in this production.
*
* @return True, if this item was added
*/
public boolean addItem(Production production, int position)
{
for (int i = 0; i<productions.length; i++)
if ((productions[i]==production) && (positions[i]==position))
return false;
Production[] newProductions = new Production[productions.length+1];
int[] newPositions = new int[positions.length+1];
System.arraycopy(productions, 0, newProductions, 0, productions.length);
System.arraycopy(positions, 0, newPositions, 0, positions.length);
newProductions[productions.length] = production;
newPositions[positions.length] = position;
productions = newProductions;
positions = newPositions;
// buildind closure for every item in state I
SymbolList productiondefinition = production.getDefinition();
// and not A=uv^w and w ist not empty
if (position<productiondefinition.getSymbolCount())
{
Symbol symbol = productiondefinition.getSymbol(position); // A=u ^symbol w
// for every item [A=u^Bv,a] in J and production B=w in G
if (symbol instanceof Nonterminal)
{
// list of all productions B
Production[] nestedproductions = grammar.getProductions(symbol);
// for alle productions B
for (int i = 0; i<nestedproductions.length; i++)
// if J doesn't contain [B=^w] , should it added
addItem(nestedproductions[i], 0);
}
}
else
addReduceAction(production);
return true;
}
/**
* Test, if all items from a other state exists in this state
*
* @param state Other state.
*
* @return True, if the state contains all items.
*/
public boolean contains(State state)
{
int i;
int j;
int position;
Production production;
boolean found;
for (i = 0; i<state.productions.length; i++)
{
production = state.productions[i];
position = state.positions[i];
found = false;
for (j = 0; (j<productions.length) && !found; j++)
found = ((productions[j]==production) && (positions[j]==position));
if (!found)
return false;
}
return true;
}
/**
* Returns the count of items in this set.
*
* @return Count of items of the core.
*/
public int getItemCount()
{
return productions.length;
}
/**
* Returns true, if this set is empty.
*
* @return True, if this set is empty.
*/
public boolean isEmpty()
{
return (productions.length==0);
}
/**
* Compares two states.
*
* @param o Other state.
*
* @return True, if the states are equal.
*/
public boolean equals(Object o)
{
if (o instanceof State)
{
State state = (State)o;
if (state.getItemCount()!=getItemCount())
return false;
// The state must contain all item from this set.
if (!contains(state))
return false;
// And this set must contain all item from the state
if (!state.contains(this))
return false;
return true;
}
return false;
}
/**
* Return the next Symbol, which follow the item.
*
* @param index Index the item.
*
* @return Symbol of the next position, otherwise the symbol for an empty list.
*/
private Symbol getNextSymbol(int index)
{
SymbolList productiondefinition;
if (positions[index]<((productiondefinition = productions[index].getDefinition()).getSymbolCount()))
return productiondefinition.getSymbol(positions[index]);
return EMPTYLIST;
}
public SymbolSet getNextTerminals()
{
SymbolSet set = new SymbolSet();
SymbolList productiondefinition;
for (int item = 0; item<productions.length; item++)
if ((positions[item]<((productiondefinition = productions[item].getDefinition()).getSymbolCount())) &&
(productiondefinition.getSymbol(positions[item]) instanceof Terminal))
set.addSymbol(productiondefinition.getSymbol(positions[item]));
return set;
}
public SymbolSet getNextNonterminals()
{
SymbolSet set = new SymbolSet();
SymbolList productiondefinition;
for (int item = 0; item<productions.length; item++)
if ((positions[item]<((productiondefinition = productions[item].getDefinition()).getSymbolCount())) &&
(productiondefinition.getSymbol(positions[item]) instanceof Nonterminal))
set.addSymbol(productiondefinition.getSymbol(positions[item]));
return set;
}
/**
* Calculates the next state by a transition through the symbol X.
*
* @param symbol A Symbol, which can be a terminal or a nonterminal symbol.
*
* @return The next state, represented by an state.
*/
public State jump(Symbol symbol)
{
State J = new State(grammar);
// For every item [A=u^Xv,a] in I
for (int i = 0; i<productions.length; i++)
{
if (getNextSymbol(i).equals(symbol))
// add [A=uX^v,a] to J
J.addItem(productions[i], positions[i]+1);
}
// jump(I,X) = closure(J)
return J;
}
/**
* Add a transition to this state.
*
* @param symbol Symbol, which forces a transition into another state.
* @param state Destination state.
*/
public boolean addShiftAction(Symbol symbol, State state)
{
for (int i = 0; i<shiftactions.length; i++)
if (shiftactions[i].symbol.equals(symbol))
return false;
ShiftAction[] newshiftactions = new ShiftAction[shiftactions.length+1];
System.arraycopy(shiftactions, 0, newshiftactions, 0, shiftactions.length);
newshiftactions[shiftactions.length] = new ShiftAction(symbol, state);
shiftactions = newshiftactions;
return true;
}
/**
* Returns the destination state of a transition.
*
* @param symbol Symbol, which force the transition.
*
* @return Destination state.
*/
public ShiftAction getShiftAction(Symbol symbol)
{
for (int i = 0; i<shiftactions.length; i++)
if (shiftactions[i].symbol.equals(symbol))
return shiftactions[i];
return null;
}
public ShiftAction[] getShiftActions()
{
return shiftactions;
}
public void addReduceAction(Production production)
{
for (int i = 0; i<reduceactions.length; i++)
if (reduceactions[i].production==production)
return;
ReduceAction[] newreduceactions = new ReduceAction[reduceactions.length+1];
for (int i = 0; i<reduceactions.length; i++)
newreduceactions[i] = reduceactions[i];
newreduceactions[reduceactions.length] = new ReduceAction(production);
reduceactions = newreduceactions;
}
public ReduceAction[] getReduceActions()
{
int count = 0;
for (int i = 0; i<productions.length; i++)
if (getNextSymbol(i).equals(EMPTYLIST)) // for all A=u^ and all symbols in FOLLOW(A)
count++;
ReduceAction[] reduceactions = new ReduceAction[count];
for (int i = 0; i<productions.length; i++)
if (getNextSymbol(i).equals(EMPTYLIST)) // for all A=u^ and all symbols in FOLLOW(A)
reduceactions[--count] = new ReduceAction(productions[i]);
return reduceactions;
}
/**
* Return a string representation of this state.
*
* @return String representation of this state.
*/
public String toString()
{
StringBuffer buffer = new StringBuffer();
SymbolList list;
for (int productionindex = 0; productionindex<grammar.getProductionCount();
productionindex++)
{
list = grammar.getProduction(productionindex).getDefinition();
for (int position = 0; position<=list.getSymbolCount(); position++)
{
for (int item = 0; item<productions.length; item++)
if ((productions[item]==grammar.getProduction(productionindex)) &&
(positions[item]==position))
{
buffer.append(productions[item].getSymbol());
buffer.append(" := ");
for (int i = 0; i<list.getSymbolCount(); i++)
{
if (i==position)
buffer.append(".");
buffer.append(list.getSymbol(i)+" ");
}
if (position==list.getSymbolCount())
buffer.append(".");
buffer.append("\n");
break;
}
}
}
return buffer.toString();
}
}