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);
        }
Exemple #2
0
        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)));
        }