/*
* JFLAP - Formal Languages and Automata Package
*
*
* Susan H. Rodger
* Computer Science Department
* Duke University
* August 27, 2009
* Copyright (c) 2002-2009
* All rights reserved.
* JFLAP is open source software. Please see the LICENSE for terms.
*
*/
package grammar;
import gui.environment.EnvironmentFrame;
import java.io.Serializable;
import java.util.*;
/**
* The grammar object is the root class for the representation of all forms of
* grammars, including regular and context-free grammars. This object simply
* maintains a structure that holds and maintains the data pertinent to the
* definition of a grammar.
*
* @author Ryan Cavalcante
*/
public abstract class Grammar implements Serializable, Cloneable {
/**
* Creates an instance of Grammar
. The created instance has
* no productions, no terminals, no variables, and specifically no start
* variable.
*/
public Grammar() {
myVariables = new HashSet();
myTerminals = new HashSet();
myStartVariable = null;
}
public abstract boolean isConverted();
/**
* Returns a copy of the Grammar object.
*
* @return a copy of the Grammar object.
*/
public Object clone() {
Grammar g;
try {
g = (Grammar) getClass().newInstance();
} catch (Throwable e) {
System.err.println("Warning: clone of grammar failed!");
return null;
}
HashMap map = new HashMap(); // old variables to new variables
String[] variables = getVariables();
for (int v = 0; v < variables.length; v++) {
String variable = variables[v];
String nvariable = new String(variables[v]);
map.put(variable, nvariable);
g.addVariable(nvariable);
}
/** set start variable. */
g.setStartVariable((String) map.get(getStartVariable()));
String[] terminals = getTerminals();
for (int t = 0; t < terminals.length; t++) {
g.addTerminal(new String(terminals[t]));
}
Production[] productions = getProductions();
for (int p = 0; p < productions.length; p++) {
String rhs = productions[p].getRHS();
String lhs = productions[p].getLHS();
g.addProduction(new Production(rhs, lhs));
}
return g;
}
/**
* Changes the start variable to variable
.
*
* @param variable
* the new start variable.
*/
public void setStartVariable(String variable) {
myStartVariable = variable;
}
/**
* Returns the start variable.
*
* @return the start variable.
*/
public String getStartVariable() {
return myStartVariable;
}
/**
* Returns true if production
is a valid production for the
* grammar. This method by default calls checkProduction
and
* returns true if and only if the method did not throw an exception.
*
* @param production
* the production.
* @return true
if the production is fine, false
* if it is not
*/
public boolean isValidProduction(Production production) {
try {
checkProduction(production);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
/**
* If a production is invalid for the grammar, this method should throw
* exceptions indicating why the production is invalid. Otherwise it should
* do nothing. This method will be called when a production is added, and
* may be called by outsiders wishing to check a production without adding
* it to a grammar.
*
* @param production
* the production
* @throws IllegalArgumentException
* if the production is in some way faulty
*/
public abstract void checkProduction(Production production);
/**
* Adds production
to the set of productions in the grammar.
*
* @param production
* the production to be added.
* @throws IllegalArgumentException
* if the production is unsuitable somehow
*/
public void addProduction(Production production) {
checkProduction(production);
GrammarChecker gc = new GrammarChecker();
/** if production already in grammar. */
if (GrammarChecker.isProductionInGrammar(production, this))
return;
myProductions.add(production);
/**
* add all new variables introduced by production to set of variables.
*/
String[] variablesInProduction = production.getVariables();
for (int k = 0; k < variablesInProduction.length; k++) {
if (!myVariables.contains(variablesInProduction[k])) {
addVariable(variablesInProduction[k]);
}
}
/**
* add all new terminals introduced by production to set of terminals.
*/
String[] terminalsInProduction = production.getTerminals();
for (int i = 0; i < terminalsInProduction.length; i++) {
if (!myTerminals.contains(terminalsInProduction[i])) {
addTerminal(terminalsInProduction[i]);
}
}
}
/**
* Adds productions
to grammar by calling addProduction for
* each production in array.
*
* @param productions
* the set of productions to add to grammar
*/
public void addProductions(Production[] productions) {
for (int k = 0; k < productions.length; k++) {
addProduction(productions[k]);
}
}
/**
* Removes production
from the set of productions in the
* grammar.
*
* @param production
* the production to remove.
*/
public void removeProduction(Production production) {
myProductions.remove(production);
GrammarChecker gc = new GrammarChecker();
/**
* Remove any variables that existed only in the production being
* removed.
*/
String[] variablesInProduction = production.getVariables();
for (int k = 0; k < variablesInProduction.length; k++) {
if (!GrammarChecker.isVariableInProductions(this,
variablesInProduction[k])) {
removeVariable(variablesInProduction[k]);
}
}
/**
* Remove any terminals that existed only in the production being
* removed.
*/
String[] terminalsInProduction = production.getTerminals();
for (int i = 0; i < terminalsInProduction.length; i++) {
if (!GrammarChecker.isTerminalInProductions(this,
terminalsInProduction[i])) {
removeTerminal(terminalsInProduction[i]);
}
}
}
/**
* Returns all productions in the grammar.
*
* @return all productions in the grammar.
*/
public Production[] getProductions() {
return (Production[]) myProductions.toArray(new Production[0]);
}
/**
* Adds terminal
to the set of terminals in the grammar.
*
* @param terminal
* the terminal to add.
*/
private void addTerminal(String terminal) {
myTerminals.add(terminal);
}
/**
* Removes terminal
from the set of terminals in the grammar.
*
* @param terminal
* the terminal to remove.
*/
private void removeTerminal(String terminal) {
myTerminals.remove(terminal);
}
/**
* Returns all terminals in the grammar.
*
* @return all terminals in the grammar.
*/
public String[] getTerminals() {
return (String[]) myTerminals.toArray(new String[0]);
}
/**
* Adds variable
to the set of variables in the grammar.
*
* @param variable
* the variable to add.
*/
private void addVariable(String variable) {
myVariables.add(variable);
}
/**
* Removes variable
from the set of variables of the grammar.
*
* @param variable
* the variable to remove.
*/
private void removeVariable(String variable) {
myVariables.remove(variable);
}
/**
* Returns all variables in the grammar.
*
* @return all variables in the grammar.
*/
public String[] getVariables() {
return (String[]) myVariables.toArray(new String[0]);
}
/**
* Returns true if production
is in the set of productions of
* the grammar.
*
* @param production
* the production.
* @return true if production
is in the set of productions of
* the grammar.
*/
public boolean isProduction(Production production) {
return myProductions.contains(production);
}
/**
* Returns true if terminal
is in the set of terminals in the
* grammar.
*
* @param terminal
* the terminal.
* @return true if terminal
is in the set of terminals in the
* grammar.
*/
public boolean isTerminal(String terminal) {
return myTerminals.contains(terminal);
}
/**
* Returns true if variable
is in the set of variables in the
* grammar.
*
* @param variable
* the variable.
* @return true if variable
is in the set of variables in the
* grammar.
*/
public boolean isVariable(String variable) {
return myVariables.contains(variable);
}
/**
* Returns a string representation of the grammar object, listing the four
* parts of the definition of a grammar: the set of variables, the set of
* terminals, the start variable, and the set of production rules.
*
* @return a string representation of the grammar object.
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(super.toString());
buffer.append('\n');
/** print variables. */
buffer.append("V: ");
String[] variables = getVariables();
for (int v = 0; v < variables.length; v++) {
buffer.append(variables[v]);
buffer.append(" ");
}
buffer.append('\n');
/** print terminals. */
buffer.append("T: ");
String[] terminals = getTerminals();
for (int t = 0; t < terminals.length; t++) {
buffer.append(terminals[t]);
buffer.append(" ");
}
buffer.append('\n');
/** print start variable. */
buffer.append("S: ");
buffer.append(getStartVariable());
buffer.append('\n');
/** print production rules. */
buffer.append("P: ");
buffer.append('\n');
Production[] productions = getProductions();
for (int p = 0; p < productions.length; p++) {
buffer.append(productions[p].toString());
buffer.append('\n');
}
return buffer.toString();
}
/**
* Changes the environment frame this automaton is in.
* @param frame the environment frame
*/
public void setEnvironmentFrame(EnvironmentFrame frame) {
myEnvFrame = frame;
}
/**
* Gets the Environment Frame the automaton is in.
* @return the environment frame.
*/
public EnvironmentFrame getEnvironmentFrame() {
return myEnvFrame;
}
public void setFilePath(String name){
fileName = name;
}
public String getFileName(){
int last = fileName.lastIndexOf("\\");
if(last == -1) last = fileName.lastIndexOf("/");
return fileName.substring(last+1);
}
public String getFilePath(){
int last = fileName.lastIndexOf("\\");
if(last == -1) last = fileName.lastIndexOf("/");
return fileName.substring(0, last+1);
}
private EnvironmentFrame myEnvFrame = null;
private String fileName ="";
/** Set of Variables. */
protected Set myVariables;
/** Set of Terminals. */
protected Set myTerminals;
/** Start variable. */
protected String myStartVariable;
/** Set of Production rules. */
protected List myProductions = new ArrayList();
}