/// <summary> /// Produces the CNF (Chomsky Normal Form) for the grammar g. /// It first eliminates epsilons, useless symbols, and unit productions. /// If Assumes that there are no epsilons, useless symbols or unit productions /// </summary> public static ContextFreeGrammar MkCNF(ContextFreeGrammar g, bool removeEpsilonsUselessSymbolsUnitsProductions) { if (removeEpsilonsUselessSymbolsUnitsProductions) { g = g.RemoveEpsilonsAndUselessSymbols(); g = g.RemoveUnitProductions(); } var productions = new Dictionary <Nonterminal, List <Production> >(); List <Nonterminal> variables = new List <Nonterminal>(g.variables); foreach (Nonterminal v in g.variables) { productions[v] = new List <Production>(); } int nonterminalID = 0; //Implements algo in Theorem 4.5, page 92-93, in Hopcroft-Ullman #region make productions of the form V --> V0...Vn or V --> a var freshVarMap = new Dictionary <GrammarSymbol, Nonterminal>(); foreach (Nonterminal v in g.variables) { foreach (Production p in g.productionMap[v]) { if (p.ContainsNoExprinals || p.IsCNF) { productions[v].Add(p); } else { GrammarSymbol[] rhs = new GrammarSymbol[p.Rhs.Length]; for (int i = 0; i < rhs.Length; i++) { if (p.Rhs[i] is Nonterminal) { rhs[i] = p.Rhs[i]; } else { Nonterminal u; if (!freshVarMap.TryGetValue(p.Rhs[i], out u)) { u = new Nonterminal(nonterminalID++); freshVarMap[p.Rhs[i]] = u; variables.Add(u); var prods = new List <Production>(); prods.Add(new Production(u, p.Rhs[i])); productions[u] = prods; } rhs[i] = u; } } productions[v].Add(new Production(v, rhs)); } } } #endregion var productionsCNF = new Dictionary <Nonterminal, List <Production> >(); List <Nonterminal> variablesCNF = new List <Nonterminal>(variables); foreach (Nonterminal v in variablesCNF) { productionsCNF[v] = new List <Production>(); } #region replace V --> V0V1...Vn (n > 2), by V --> V0U0, U0 --> V1U1, ..., Un-2 --> Vn-1Vn foreach (Nonterminal v in variables) { foreach (Production p in productions[v]) { if (p.IsCNF) { productionsCNF[v].Add(p); } else { Nonterminal x = v; Nonterminal y = new Nonterminal(nonterminalID++); variablesCNF.Add(y); productionsCNF[y] = new List <Production>(); for (int i = 0; i < p.Rhs.Length - 2; i++) { productionsCNF[x].Add(new Production(x, p.Rhs[i], y)); if (i < p.Rhs.Length - 3) { x = y; y = new Nonterminal(nonterminalID++); variablesCNF.Add(y); productionsCNF[y] = new List <Production>(); } } productionsCNF[y].Add(new Production(y, p.Rhs[p.Rhs.Length - 2], p.Rhs[p.Rhs.Length - 1])); } } } #endregion ContextFreeGrammar cnf = new ContextFreeGrammar(variablesCNF, g.startSymbol, productionsCNF); return(cnf); }