/// <summary> /// Simplify context-free grammar by removing unreachable symbols and productions and productions of /// the form V ::= V. /// </summary> /// <param name="grammar">target grammar</param> /// <returns>simplified grammar</returns> public static CFG Simplify(this CFG grammar) { OrderedHashSet <Production> productions = new OrderedHashSet <Production>(); OrderedHashSet <string> newSymbols = new OrderedHashSet <string>(), seenSymbols = new OrderedHashSet <string>(); newSymbols.Add(grammar.startVariable); while (newSymbols.Count() > 0) { foreach (string symbol in newSymbols) { seenSymbols.Add(symbol); } OrderedHashSet <string> nextSymbols = new OrderedHashSet <string>(); foreach (Production production in grammar.productions) { if (newSymbols.Contains(production.lhs) && (production.rhs.Length != 1 || production.rhs[0] != production.lhs)) { productions.Add(production); foreach (string symbol in production.rhs) { if (!seenSymbols.Contains(symbol)) { nextSymbols.Add(symbol); } } } } newSymbols = nextSymbols; } return(verifyConsistency(grammar, new CFG(grammar.startVariable, productions))); }
/// <summary> /// Checks whether the grammar has a left-recursive production, i.e., /// of the form `v ::= v s1 s2...` (can also be indirect). /// </summary> /// <param name="grammar">context-free grammar</param> /// <returns>whether grammar has left-recursion</returns> public static bool HasLeftRecursion(this CFG grammar) { foreach (string variable in grammar.Variables()) { OrderedHashSet <string> reachableVariables = new OrderedHashSet <string>(); reachableVariables.Add(variable); int n = 0; while (reachableVariables.Count() > n) { n = reachableVariables.Count(); OrderedHashSet <string> newReachableVariables = new OrderedHashSet <string>(); foreach (string reachableVariable in reachableVariables) { foreach (Production production in grammar.productions) { if (production.lhs == reachableVariable && production.rhs.Length > 0) { string first = production.rhs[0]; if (first == variable) { return(true); } else if (grammar.Variables().Contains(first)) { newReachableVariables.Add(first); } } } } foreach (string newVariable in newReachableVariables) { reachableVariables.Add(newVariable); } } } return(false); }