package finiteAutomata;
import java.util.Random;
import java.util.Vector;
/**
* A non-empty string of variables and terminals such as occur in grammar
* derivations (supports the CNF class).
*
*
Data Fields: Each StringVarTerm has a Vector (code) of Integer
* codes to represent the string, a counter (vars) telling how many
* variables are in the string, a Vector (derivation) of String objects
* showing the sequence of strings used in deriving this string, and an
* Alphabet (alpha) of allowable terminal symbols.
*
*
Example (encoding/decoding):
* Suppose the Alphabet is {a,b,c}. The integers 1, 2, 3 are used to
* represent, respectively, the terminal symbols a, b, and c. 0
* represents the start variable v0, -1 represents v1, -2 represents v2,
* and so on. Thus, the string "c a v1 v2 b a v2" would be encoded by
* the integer sequence "3, 1, -1, -2, 2, 1, -2". Note that
* terminals are represented by positive codes and variables are
* represented by non-positive codes.
*
* @author Barbara Wahl
* @version Fall 2007
*/
public class StringVarTerm {
// ** DATA FIELDS **
/**
* sequence of Integer codes for this StringVarTerm
*/
protected Vector code;
/**
* number of variables in this StringVarTerm (vars == 0
* if this represents a string of terminal symbols)
*/
protected int vars;
/**
* alphabet of terminal symbols
*/
protected Alphabet alpha;
/**
* sequence of Strings showing how this StringVarTerm is derived
* from start (v0)
*/
protected Vector derivation;
/**
* 1-parameter constructor, creates the StringVarTerm representing the start
* string, "v0"
* @param S Alphabet of terminal symbols
* @post creates the "start" string consisting of only the start variable, "v0"
* (alpha = S, vars = 1, derivation is empty)
*/
public StringVarTerm(Alphabet S)
{
alpha = S;
vars = 1;
code = new Vector(); // allocate Vector for code
code.add(new Integer(0)); // 0 = encoding for v0
derivation = new Vector(); // empty derivation
}
/**
* Returns number of steps to derive this StringVarTerm.
* @return number of steps to derive this StringVarTerm from
* "v0" (where 0 steps are needed to derive "v0")
*/
public int numSteps()
// post: returns number of steps to derive this StringVarTerm,
// (0 steps are needed to derive the start string "v0")
{
return this.derivation.size();
}
/**
* Returns number of variables.
* @return this.vars
*/
public int vars()
{
return this.vars;
}
/**
* Returns a deep copy of this StringVarTerm.
* @return a new StringVarTerm with all the same data fields as this
* @post the new object is completely independent of the original
* (the derivation and code Vectors are deep-copied)
*/
public StringVarTerm copy()
{
StringVarTerm newString = new StringVarTerm(alpha);
newString.vars = vars;
newString.code = code();
newString.derivation = derivation();
return newString;
}
/**
* Returns a deep copy of this.derivation.
* @return a new derivation Vector filled with new String objects
*/
public Vector derivation()
{
Vector v = new Vector();
for(int i=0; i"),
* with "this" string appended at the end
*/
public void printDerivation()
{
for(int i=0; i ");
}
System.out.println(this.toPrettyString());
}
/**
* Returns a "pretty" representation of the string represented
* by this StringVarTerm.
* @return a "pretty" String representation of this StringVarTerm
* (decodes the "code" Vector, inserts 'v's and spaces)
*/
public String toPrettyString()
{
StringBuffer s = new StringBuffer();
int num;
char c;
// iterate through this.code and append appropriate chars
// to s (separated by spaces)
for(int i=0; i term) then r.term() must be a
* symbol in this.alpha
* @post this StringVarTerm is left unchanged
*/
public StringVarTerm applyRule(CNFRule r)
{
StringVarTerm temp = this.copy(); // to insure non-destruction of this
if(!temp.matches(r)) // nothing to do -- rule does not apply
{
System.out.println("rule does not apply! (variable mis-match)");
return temp;
}
// otherwise, locate position of left-most variable
int pos = temp.leftMostVarIndex();
if(r.type() == 0)
{ // type 0 rule, vn -> vi vj
// 0 - r.var2() encodes r.var2(); 0 - r.var3() encodes r.var3()
temp.code.insertElementAt(new Integer(0 - r.var2()),pos+1);
temp.code.insertElementAt(new Integer(0 - r.var3()),pos+2);
temp.code.remove(pos);
temp.vars = vars + 1;
}
if(r.type() == 1)
{ // type 1 rule, vn -> terminal
// first, make sure r.term() is in alphabet
int index = temp.alpha.indexOf(r.term());
if(index < 0)
return temp; // r.term() not in alphabet
// T.charAt(index) is encoded by index+1
temp.code.insertElementAt(new Integer(index+1),pos+1);
temp.code.remove(pos);
temp.vars = vars - 1;
}
temp.derivation.add(this.toPrettyString());
return temp;
}
/**
* Returns the decoded value of the given position in this.code, assuming
* that position is a coded variable.
* @param i position of interest in this code
* @pre 0 <= i < code.length()
* @return assuming code.elementAt(i) has a non-positive value,
* returns the corresponding variable number
*/
protected int decodeVar(int i)
{
return (0 - ((Integer)code.elementAt(i)).intValue());
}
/**
* Returns the index (position) of the left-most variable in this
* StringVarTerm.
* @return the index of the left-most variable in this StringVarTerm,
* or -1 (if no variables are present)
*/
public int leftMostVarIndex()
{
if(vars == 0) // no variables
return -1;
int i=0;
while(((Integer)code.elementAt(i)).intValue() > 0) // not var
i++;
return i;
}
/**
* Tests whether a given rule applies to the left-most variable in this
* StringVarTerm.
* @param r the rule to be tested
* @return true iff the left-most variable in this StringVarTerm is
* the same as r.var1, the LHS of rule r
* @pre r is not null
*/
public boolean matches(CNFRule r)
{
int i = leftMostVarIndex(); // position of left-most variable
if(i<0)
return false; // no variable exists
// convert from Integer to int
int leftMostVar = ((Integer)code.elementAt(i)).intValue();
// 0 - r.var1() is the int code for r.var1()
if(leftMostVar == 0 - r.var1())
return true; // int codes match -- success!
else return false; // no match
}
/**
* Tests whether a given String is a non-empty string of terminals and
* this StringVarTerm represents the same string of terminals.
* @param s the String to be tested
* @return true iff "this" and s represent exactly the same non-empty
* string of terminal symbols
* @pre s is not null
*/
public boolean equalTermString(String s)
{
// false if s is empty or if "this" contains any variables
if(s.length() == 0 && this.vars > 0)
return false;
if(alpha.indexArray(s,new int[s.length()]))
// if s is a string of terminals from this.alpha...
{
// convert this to a string of terminals & compare with s
String termString = this.toTermString();
return termString.equals(s);
}
else
return false;
}
/**
* Tests whether "this" and another StringVarTerm represent the
* same string.
* @param other the StringVarTerm with which to compare this
* @return true iff "this" and other represent the same string
* of variables and terminals (perhaps with different derivations)
* @pre other is not null
*/
public boolean equalString(StringVarTerm other)
{
String s1 = this.toPrettyString();
String s2 = other.toPrettyString();
return s1.equals(s2);
}
// ** TEST METHOD **
public static void main(String[] args) {
// create Alphabet = {a,b,c}
Alphabet alpha = new Alphabet("abc");
// create "start" string using alphabet {a,b,c}
StringVarTerm str = new StringVarTerm(alpha);
str.printStringVarTerm();
// create some rules
CNFRule[] rule = new CNFRule[4];
rule[0] = new CNFRule(0,1,2); // create the rule "v0 -> v1 v2"
rule[1] = new CNFRule(1,'a'); // create the rule "v1 -> a"
rule[2] = new CNFRule(2,'b'); // create the rule "v2 -> b"
rule[3] = new CNFRule(1,1,1); // // create the rule "v1 -> v1 v1"
// apply rule v0 -> v1 v2
str = str.applyRule(rule[0]);
System.out.println("After calling str.applyRule, we have:");
str.printStringVarTerm();
// randomly try to apply a rule 40 times
Random rand = new Random(35); // new random number generator
int randInt;
for(int i=0; i<40; i++)
{
randInt = rand.nextInt(3);
str = str.applyRule(rule[randInt+1]); // apply rule 1, 2, or 3
// print str
System.out.println("After calling str.applyRule, we have:");
str.printStringVarTerm();
}
// print the final result
str.printStringVarTerm();
}
}