/// <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> /// Generates a CNF that accepts the prefix closure of a given grammar. /// </summary> /// <param name="g">the original grammar</param> /// <returns>the prefix closure</returns> public static ContextFreeGrammar getCNFPrefixClosure(ContextFreeGrammar g) { if (g == null) { return(g); } if (!g.IsInCNF()) { g = getEquivalentCNF(g); } if (g == null) { return(g); } var prefixClosure = getPrefixClosure(g); prefixClosure = getEquivalentCNF(prefixClosure); // !!ATTENTION!! this may remove old productions var productions = g.GetProductions(); productions = productions.Concat(prefixClosure.GetProductions()); return(new ContextFreeGrammar(prefixClosure.StartSymbol, productions)); }
/// <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); }
/// <summary> /// Generates a CFG that accepts the prefix closure of a given grammar. /// </summary> /// <param name="g">the original grammar</param> /// <returns>the prefix closure</returns> public static ContextFreeGrammar getPrefixClosure(ContextFreeGrammar g) { Func <Nonterminal, Nonterminal> prefixFor = delegate(Nonterminal x) { return(new Nonterminal(x.Name + "PREFIX")); }; if (g == null) { return(g); } if (!g.IsInCNF()) { g = getEquivalentCNF(g); } if (g == null) { return(g); } Nonterminal prefixStart = prefixFor(g.StartSymbol); var prefixProductions = new List <Production>(); foreach (Production p in g.GetProductions()) { //add original prefixProductions.Add(p); Nonterminal prefixNT = prefixFor(p.Lhs); if (p.Rhs.Length == 2) // case: X->AB ==> X' ->A' | AB' { prefixProductions.Add(new Production(prefixNT, new GrammarSymbol[] { p.Rhs[0], prefixFor((Nonterminal)p.Rhs[1]) })); prefixProductions.Add(new Production(prefixNT, new GrammarSymbol[] { prefixFor((Nonterminal)p.Rhs[0]) })); } else // case: X->a ==> X'->a { prefixProductions.Add(new Production(prefixNT, new GrammarSymbol[] { p.Rhs[0] })); } } var res = new ContextFreeGrammar(prefixStart, prefixProductions); res.setAcceptanceForEmptyString(true); return(res); }