/*
* 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.grammar;
import java.io.Serializable;
import net.sourceforge.chaperon.grammar.production.Production;
import net.sourceforge.chaperon.grammar.production.ProductionList;
import net.sourceforge.chaperon.grammar.symbol.SymbolList;
import net.sourceforge.chaperon.grammar.symbol.NonTerminalSymbol;
import net.sourceforge.chaperon.grammar.symbol.TerminalSymbol;
//import net.sourceforge.chaperon.grammar.token.Comment;
import net.sourceforge.chaperon.grammar.token.Token;
import net.sourceforge.chaperon.grammar.token.TokenList;
//import net.sourceforge.chaperon.grammar.token.Whitespace;
import net.sourceforge.chaperon.grammar.token.definition.EndOfFile;
/**
* This class contains a grammar for building a parser table
*
* @author Stephan Michels
* @version $Revision: 1.7 $ $Date: 2002/05/06 16:22:56 $
*/
public class Grammar implements Serializable, Cloneable
{
// Uniform resource indentifier
private String _uri = "http://chaperon.sourceforge.net/grammar/noname/1.0";
// Tokens
private TokenList _tokenlist = new TokenList();
// Indix from the non terminal symbol for the start symbol
private NonTerminalSymbol _ssymbol;
//private TokenList _universaltokenlist = new TokenList();
private TokenList _ignorabletokenlist = new TokenList();
// Productions
private ProductionList _productionlist = new ProductionList();
/**
* Creates a empty grammar
* Only EOF is definied as token.
*/
public Grammar()
{
_tokenlist.addToken(new Token(TerminalSymbol.valueOf("EOF"), new EndOfFile()));
_tokenlist.setOwner(this);
//_universaltokenlist.setOwner(this);
_ignorabletokenlist.setOwner(this);
_productionlist.setOwner(this);
}
/**
* Set the uniform resource identifier of the grammar
*
* @param uri Uniform resource identifier of the grammar
*/
public void setURI(String uri)
{
if (uri == null)
throw new NullPointerException();
_uri = uri;
}
/**
* Return the uniform resource identifier of the grammar
*
* @return Uniform resource identifier of the grammar
*/
public String getURI()
{
return _uri;
}
/**
* Returns the list of tokens, which this grammar contains
*
* @return List of tokens
*/
public TokenList getTokenList()
{
return _tokenlist;
}
/**
*
*
* @return
*/
public TokenList getIgnorableTokenList()
{
return _ignorabletokenlist;
}
/**
*
*
* @return
*/
/*public TokenList getUniversalTokenList()
{
return _universaltokenlist;
}*/
/**
* Returns the list of productions, which this grammar contains
*
* @return List of productions
*/
public ProductionList getProductionList()
{
return _productionlist;
}
/**
* Return all used symbol in this grammar
*
* @return List of symbols
*/
public SymbolList getSymbols()
{
SymbolList list = new SymbolList(true);
list.addSymbolList(_tokenlist.getSymbols());
list.addSymbolList(_productionlist.getSymbols());
return list;
}
/**
* Set the a symbol a start symbol
*
* @param ssymbol
*/
public void setStartSymbol(NonTerminalSymbol ssymbol)
{
if (ssymbol == null)
throw new NullPointerException();
_ssymbol = ssymbol;
}
/**
* Returns the start symbol
*
* @return Start symbol
*/
public NonTerminalSymbol getStartSymbol()
{
return _ssymbol;
}
/**
* This method validates the grammer
*
* @return Return a SyntaxErrorException, if this
* grammar isn't correct
*/
public SyntaxErrorException validate()
{
if (_tokenlist.getTokenCount() <= 0)
return new SyntaxErrorException("No tokens are defined");
if (_productionlist.getProductionCount() <= 0)
return new SyntaxErrorException("No productions are defined");
if (_productionlist.getProductionList(_ssymbol).getSize() <= 0)
return new SyntaxErrorException("Start symbol is not set");
SymbolList symbols = getSymbols();
SymbolList tsymbols = symbols.getTerminalSymbols();
SymbolList ntsymbols = symbols.getNonTerminalSymbols();
int i;
// Test, if all terminal symbol are well defined
for (i = 0; i < tsymbols.getSymbolCount(); i++)
if (!_tokenlist.contains(tsymbols.getSymbol(i)))
return new SyntaxErrorException(_tokenlist + "\n" + _productionlist
+ "Terminal symbol \""
+ tsymbols.getSymbol(i)
+ "\" is not defined through a token");
// Test, if all non terminal symbol are well defined
for (i = 0; i < ntsymbols.getSymbolCount(); i++)
if (!_productionlist.contains(ntsymbols.getSymbol(i)))
return new SyntaxErrorException(_productionlist
+ "Nonterminal symbol \""
+ ntsymbols.getSymbol(i)
+ "\" is not defined through a production");
return null;
}
/**
*
*
* @return
*/
public String toString()
{
return _tokenlist.toString() + "\n" + _productionlist.toString();
}
/**
* Creates a clone of a grammar.
*
* @return
*
* @throws CloneNotSupportedException
*/
public Object clone() throws CloneNotSupportedException
{
Grammar clone = new Grammar();
clone._uri = new String(_uri);
clone._tokenlist = (TokenList) _tokenlist.clone();
clone._tokenlist.setOwner(clone);
//clone._universaltokenlist = (TokenList) _universaltokenlist.clone();
//clone._universaltokenlist.setOwner(clone);
clone._ignorabletokenlist = (TokenList) _ignorabletokenlist.clone();
clone._ignorabletokenlist.setOwner(clone);
clone._ssymbol = _ssymbol;
clone._productionlist = (ProductionList) _productionlist.clone();
clone._productionlist.setOwner(clone);
return clone;
}
}