/// <summary> /// Generates a CNF for a given grammar or returns null if the Grammar doesn't produce any words. /// </summary> /// <param name="g">the original grammar</param> /// <returns>the CNF or null</returns> public static ContextFreeGrammar getEquivalentCNF(ContextFreeGrammar g) { if (g == null) { return(null); } if (g.IsInCNF()) { return(g); } try { ContextFreeGrammar res = ContextFreeGrammar.MkCNF(g); //handle empty string res.setAcceptanceForEmptyString(g.acceptsEmptyString()); return(res); } catch (AutomataException e) { if (g.acceptsEmptyString()) { var res = new ContextFreeGrammar(new Nonterminal("S"), new Production[] { new Production(new Nonterminal("S"), new GrammarSymbol[] { new Nonterminal("S"), new Nonterminal("S") }) }); res.setAcceptanceForEmptyString(true); return(res); } return(null); } }
/// <summary> /// Checks if a word is recognized by the given grammar. (CYK-algorithm) /// </summary> /// <param name="grammar">the grammar</param> /// <param name="word">the word</param> /// <returns>true, if there exists a dereviation from the startsymbol to the word</returns> public static bool isWordInGrammar(ContextFreeGrammar grammar, string word) { if (word == null || grammar == null) { return(false); } if (!grammar.IsInCNF()) { grammar = getEquivalentCNF(grammar); } if (grammar == null) { return(false); } //empty word if (word.Length == 0) { return(grammar.acceptsEmptyString()); } //CYK var cyk_table = cyk(grammar, word); return(cyk_table[word.Length - 1][0].Item1.Contains(grammar.StartSymbol)); }
/// <summary> /// Finds the longest prefix of a given word that is still recognized by a given grammar. (CYK algorithm with prefix closure) /// </summary> /// <param name="grammar">the grammar</param> /// <param name="word">the word</param> /// <returns>-1 if the grammar is empty; -2 if the word is in the grammar; n (if the substring up to index n is the longest prefix)</returns> public static int longestPrefixLength(ContextFreeGrammar grammar, string word) { if (word == null || grammar == null) { return(-1); } if (!grammar.IsInCNF()) { grammar = getEquivalentCNF(grammar); } if (grammar == null) { return(-1); } //empty word if (word.Length == 0) { if (grammar.acceptsEmptyString()) { return(-2); } return(0); } //prefix closure var prefixGrammar = getCNFPrefixClosure(grammar); //CYK var cyk_table = cyk(prefixGrammar, word); //check if word was in original grammar if (cyk_table[word.Length - 1][0].Item1.Contains(grammar.StartSymbol)) { return(-2); } //check for startsymbol in first row for (int i = word.Length - 1; i >= 0; i--) { if (cyk_table[i][0].Item1.Contains(prefixGrammar.StartSymbol)) { return(i + 1); } } return(0); }
private static HashSet <string> generateWordsWithLength(ContextFreeGrammar cnf, int length, Dictionary <Nonterminal, Dictionary <int, HashSet <string> > > dp) { HashSet <string> res = new HashSet <string>(); if (cnf == null) { return(res); //empty grammar -> can't generate any words } if (length == 0) //case: length = 0 { if (cnf.acceptsEmptyString()) { res.Add(""); } } else if (length == 1) //case: length = 1 { foreach (Nonterminal nt in cnf.Variables) { //init dp[nt] Dictionary <int, HashSet <string> > curDP = new Dictionary <int, HashSet <string> >(); dp.Add(nt, curDP); //find words of length 1 HashSet <string> l = new HashSet <string>(); foreach (Production p in cnf.GetProductions(nt)) { if (p.IsSingleExprinal) { l.Add(p.Rhs[0].ToString()); } } curDP.Add(1, l); if (nt.Equals(cnf.StartSymbol)) { res = l; } } } else //case: length > 1 { foreach (KeyValuePair <Nonterminal, Dictionary <int, HashSet <string> > > entry in dp) { Nonterminal cur = entry.Key; Dictionary <int, HashSet <string> > curDP = entry.Value; HashSet <string> curSet = new HashSet <string>(); curDP.Add(length, curSet); if (cur.Equals(cnf.StartSymbol)) { res = curSet; } foreach (Production p in cnf.GetProductions(entry.Key)) { if (p.Rhs.Length != 2) { continue; //ignore productions that don't have form X->AB } Nonterminal left = (Nonterminal)p.Rhs[0]; Dictionary <int, HashSet <string> > leftDP = null; dp.TryGetValue(left, out leftDP); Nonterminal right = (Nonterminal)p.Rhs[1]; Dictionary <int, HashSet <string> > rightDP = null; dp.TryGetValue(right, out rightDP); for (int leftPart = 1; leftPart < length; leftPart++) { int rightPart = length - leftPart; HashSet <string> leftPossibilities = null; leftDP.TryGetValue(leftPart, out leftPossibilities); HashSet <string> rightPossibilities = null; rightDP.TryGetValue(rightPart, out rightPossibilities); foreach (string leftString in leftPossibilities) { foreach (string rightString in rightPossibilities) { curSet.Add(leftString + rightString); } } } } } } return(res); }