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(); } }