private static CFG verifyConsistency(CFG oldGrammar, CFG newGrammar) { OrderedHashSet <string> oldVariables = oldGrammar.Variables(); foreach (string terminal in newGrammar.Terminals()) { if (oldVariables.Contains(terminal)) { throw new Exception($"grammar is malformed: variable {terminal} cannot be derived"); } } foreach (string variable in newGrammar.Variables()) { bool variableIsDerived = false; foreach (Production production in newGrammar.productions) { if (production.lhs == variable) { variableIsDerived = true; break; } } if (!variableIsDerived) { throw new Exception($"grammar is malformed: variable {variable} cannot be derived"); } } return(newGrammar); }
private string PrintVariableInterfaces() { StringBuilder builder = new StringBuilder(); foreach (string variable in grammar.Variables()) { builder.Append(PrintVariableInterface(variable)); } return(builder.ToString()); }
/// <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); }
/// <summary> /// Removes left-recursive productions from the grammar. /// Implementation of Paull's algorithm. /// </summary> /// <param name="grammar">target grammar</param> /// <returns>grammar without left recursion</returns> public static CFG RemoveLeftRecursion(this CFG grammar) { if (!grammar.HasLeftRecursion()) { return(grammar); } grammar = grammar.Simplify().RemoveEpsilonProductions(); if (!grammar.HasLeftRecursion()) { return(grammar); } bool epsilonIsDerived = grammar.productions.Contains(new Production(grammar.startVariable)); OrderedHashSet <Production> productions = new OrderedHashSet <Production>(); foreach (Production production in grammar.productions) { productions.Add(production); } if (epsilonIsDerived) { productions.Remove(new Production(grammar.startVariable)); } List <string> variables = new List <string>(grammar.Variables()); OrderedHashSet <string> usedSymbols = new OrderedHashSet <string>(); foreach (string symbol in grammar.Symbols()) { usedSymbols.Add(symbol); } for (int i = 0; i < variables.Count; ++i) { string vi = variables[i]; for (int j = 0; j < i; ++j) { string vj = variables[j]; OrderedHashSet <Production> toRemove = new OrderedHashSet <Production>(); OrderedHashSet <Production> toAdd = new OrderedHashSet <Production>(); foreach (Production production in productions) { if (production.lhs == vi && production.rhs.Length > 0 && production.rhs[0] == vj) { toRemove.Add(production); foreach (Production otherProduction in productions) { if (otherProduction.lhs == vj) { List <string> newRHS = new List <string>(); newRHS.AddRange(otherProduction.rhs); newRHS.AddRange(production.rhs.Skip(1)); toAdd.Add(new Production(vi, newRHS.ToArray())); } } break; } } foreach (Production addedProduction in toAdd) { productions.Add(addedProduction); } foreach (Production removedProduction in toRemove) { productions.Remove(removedProduction); } } OrderedHashSet <Production> productionsWithoutViDirectLeftRecursion = new OrderedHashSet <Production>(); OrderedHashSet <Production> newViProductions = new OrderedHashSet <Production>(); foreach (Production production in productions) { if (production.lhs != vi) { productionsWithoutViDirectLeftRecursion.Add(production); } else { newViProductions.Add(production); } } foreach (Production newViProduction in RemoveDirectLeftRecursion(usedSymbols, newViProductions)) { productionsWithoutViDirectLeftRecursion.Add(newViProduction); } productions = productionsWithoutViDirectLeftRecursion; } if (epsilonIsDerived) { productions.Add(new Production(grammar.startVariable)); } return(verifyConsistency(grammar, new CFG(grammar.startVariable, productions))); }