private ContextFreeGrammar(GrammarSymbol[] nonterminals, GrammarSymbol[] terminals,
            Production[] rules, GrammarSymbol starting)
        {
            // doesnt check for exception, careful

            this.nonterminals = nonterminals;
            this.terminals = terminals;
            this.alphabet = nonterminals.Concat(terminals).ToArray();
            this.rules = rules;
            this.starting = starting;
        }
        public ContextFreeGrammar GetChomskyNormalForm()
        {
            var newNonterminals = new List<GrammarSymbol>(nonterminals);
            var newRules = new List<Production>(rules);
            var toBeAddedRules = new List<Production>();

            var newStarting = new GrammarSymbol("S0", false);
            newNonterminals.Add(newStarting);
            newRules.Add(new Production(newStarting, new Sentence(new[] { starting })));

            for (int i = 0; i < newRules.Count; i++)
            {
                var rule = newRules[i];

                var sentence = rule.DirectDerivative.ToArray();
                if (rule.DirectDerivative.HasNonsolitaryTerminal)
                {
                    var encountered = new List<GrammarSymbol>();
                    for (int j = 0; j < sentence.Length; j++)
                    {
                        var symbol = sentence[j];

                        if (symbol.IsTerminal)
                        {
                            string label = "N" + symbol.ToString();
                            GrammarSymbol newSymbol = encountered.FirstOrDefault((s) => s.Matches(label));
                            if (newSymbol == null)
                            {
                                newSymbol = new GrammarSymbol(label, false);
                                encountered.Add(newSymbol);
                                newNonterminals.Add(newSymbol);
                                toBeAddedRules.Add(new Production(newSymbol, new Sentence(new[] { symbol })));
                            }

                            sentence[j] = newSymbol;
                        }
                    }
                }

                newRules[i] = new Production(rule.Original, new Sentence(sentence));
            }
            newRules.AddRange(toBeAddedRules);
            toBeAddedRules = new List<Production>();

            for (int i = 0; i < newRules.Count; i++)
            {
                var rule = newRules[i];

                var sentence = rule.DirectDerivative;
                var newSentence = sentence.ToArray();
                if (sentence.HasMoreThanTwoNonterminals)
                {
                    GrammarSymbol nextSymbol = rule.Original;
                    int n = newSentence.Length;
                    for (int j = 0; j < n - 2; j++)
                    {
                        var currentSymbol = nextSymbol;
                        nextSymbol = new GrammarSymbol(rule.Original.ToString() + (i + 1).ToString(), false);
                        newNonterminals.Add(nextSymbol);
                        toBeAddedRules.Add(new Production(currentSymbol, new Sentence(new[] { newSentence[j], nextSymbol })));
                    }
                    newRules[i] = new Production(nextSymbol, new Sentence(new[] { newSentence[n - 2], newSentence[n - 1] }));
                    // order is somewhat scrambled
                }
            }
            newRules.AddRange(toBeAddedRules);
            toBeAddedRules = new List<Production>();

            bool noEpsilonLeft = false;
            while (!noEpsilonLeft)
            {
                noEpsilonLeft = true;
                foreach (var rule in newRules)
                    if (rule.DirectDerivative.IsEmpty && rule.Original != newStarting)
                    {

                        GrammarSymbol nullable = rule.Original;
                        bool isLastRule = newRules.Count((r) => r.Original == nullable) == 0;
                        if (!isLastRule)
                            for (int i = 0; i < newRules.Count(); i++)
                            {
                                var oldSymbol = newRules[i].Original;
                                var sentence = newRules[i].DirectDerivative.ToArray();
                                int n = sentence.Length;
                                Debug.Assert(n < 3);

                                if (n == 1 && sentence[0] == nullable)
                                    AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty));
                                else if (n == 2)
                                {
                                    if (sentence[0] == sentence[1] && sentence[0] == nullable)
                                    {
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty));
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] })));
                                    }
                                    else if (sentence[0] == nullable)
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[1] })));
                                    else if (sentence[1] == nullable)
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] })));
                                }
                            }
                        else
                        {
                            for (int i = 0; i < newRules.Count(); i++)
                            {
                                var oldSymbol = newRules[i].Original;
                                var sentence = newRules[i].DirectDerivative.ToArray();
                                int n = sentence.Length;
                                Debug.Assert(n < 3);

                                if (n == 1 && sentence[0] == nullable)
                                    AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty));
                                else if (n == 2)
                                {
                                    if (sentence[0] == sentence[1] && sentence[0] == nullable)
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty));
                                    else if (sentence[0] == nullable)
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[1] })));
                                    else
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] })));
                                }
                            }
                            newNonterminals.Remove(nullable);
                        }
                        newRules.Remove(rule);
                        toBeAddedRules = new List<Production>();
                        noEpsilonLeft = false;
                        break;
                    }
            }

            bool noUnitRuleLeft = false;
            while (!noUnitRuleLeft)
            {
                noUnitRuleLeft = true;
                foreach (var rule in newRules)
                {
                    bool isUnitRule = rule.DirectDerivative.Length == 1 && !rule.DirectDerivative.First().IsTerminal;
                    if (isUnitRule)
                    {
                        newRules.Remove(rule);

                        var toBeReplaced = rule.DirectDerivative.First();
                        var replacement = rule.Original;
                        for (int i = 0; i < newRules.Count(); i++)
                        {
                            var oldSymbol = newRules[i].Original;
                            var sentence = newRules[i].DirectDerivative.ToArray();

                            if (oldSymbol == toBeReplaced)
                                toBeAddedRules.Add(new Production(replacement, new Sentence(sentence)));
                        }
                        newNonterminals.Remove(toBeReplaced);
                        newRules.AddRange(toBeAddedRules);
                        toBeAddedRules = new List<Production>();

                        noUnitRuleLeft = false;
                        break;
                    }
                }
            }

            return new ContextFreeGrammar(newNonterminals.ToArray(), this.terminals, newRules.ToArray(), newStarting);
        }
        private void AddIfNotExist(ref List<Production> newRules, Production toBeAdded)
        {
            foreach (Production rule in newRules)
                if (rule.Original == toBeAdded.Original
                 && rule.DirectDerivative.SequenceEqual(toBeAdded.DirectDerivative))
                    return;

            newRules.Add(toBeAdded);
        }
        public ContextFreeGrammar GetChomskyNormalForm()
        {
            var newNonterminals = new List <GrammarSymbol>(nonterminals);
            var newRules        = new List <Production>(rules);
            var toBeAddedRules  = new List <Production>();


            var newStarting = new GrammarSymbol("S0", false);

            newNonterminals.Add(newStarting);
            newRules.Add(new Production(newStarting, new Sentence(new[] { starting })));

            for (int i = 0; i < newRules.Count; i++)
            {
                var rule = newRules[i];

                var sentence = rule.DirectDerivative.ToArray();
                if (rule.DirectDerivative.HasNonsolitaryTerminal)
                {
                    var encountered = new List <GrammarSymbol>();
                    for (int j = 0; j < sentence.Length; j++)
                    {
                        var symbol = sentence[j];

                        if (symbol.IsTerminal)
                        {
                            string        label     = "N" + symbol.ToString();
                            GrammarSymbol newSymbol = encountered.FirstOrDefault((s) => s.Matches(label));
                            if (newSymbol == null)
                            {
                                newSymbol = new GrammarSymbol(label, false);
                                encountered.Add(newSymbol);
                                newNonterminals.Add(newSymbol);
                                toBeAddedRules.Add(new Production(newSymbol, new Sentence(new[] { symbol })));
                            }

                            sentence[j] = newSymbol;
                        }
                    }
                }

                newRules[i] = new Production(rule.Original, new Sentence(sentence));
            }
            newRules.AddRange(toBeAddedRules);
            toBeAddedRules = new List <Production>();


            for (int i = 0; i < newRules.Count; i++)
            {
                var rule = newRules[i];

                var sentence    = rule.DirectDerivative;
                var newSentence = sentence.ToArray();
                if (sentence.HasMoreThanTwoNonterminals)
                {
                    GrammarSymbol nextSymbol = rule.Original;
                    int           n          = newSentence.Length;
                    for (int j = 0; j < n - 2; j++)
                    {
                        var currentSymbol = nextSymbol;
                        nextSymbol = new GrammarSymbol(rule.Original.ToString() + (i + 1).ToString(), false);
                        newNonterminals.Add(nextSymbol);
                        toBeAddedRules.Add(new Production(currentSymbol, new Sentence(new[] { newSentence[j], nextSymbol })));
                    }
                    newRules[i] = new Production(nextSymbol, new Sentence(new[] { newSentence[n - 2], newSentence[n - 1] }));
                    // order is somewhat scrambled
                }
            }
            newRules.AddRange(toBeAddedRules);
            toBeAddedRules = new List <Production>();


            bool noEpsilonLeft = false;

            while (!noEpsilonLeft)
            {
                noEpsilonLeft = true;
                foreach (var rule in newRules)
                {
                    if (rule.DirectDerivative.IsEmpty && rule.Original != newStarting)
                    {
                        GrammarSymbol nullable   = rule.Original;
                        bool          isLastRule = newRules.Count((r) => r.Original == nullable) == 0;
                        if (!isLastRule)
                        {
                            for (int i = 0; i < newRules.Count(); i++)
                            {
                                var oldSymbol = newRules[i].Original;
                                var sentence  = newRules[i].DirectDerivative.ToArray();
                                int n         = sentence.Length;
                                Debug.Assert(n < 3);

                                if (n == 1 && sentence[0] == nullable)
                                {
                                    AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty));
                                }
                                else if (n == 2)
                                {
                                    if (sentence[0] == sentence[1] && sentence[0] == nullable)
                                    {
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty));
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] })));
                                    }
                                    else if (sentence[0] == nullable)
                                    {
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[1] })));
                                    }
                                    else if (sentence[1] == nullable)
                                    {
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] })));
                                    }
                                }
                            }
                        }
                        else
                        {
                            for (int i = 0; i < newRules.Count(); i++)
                            {
                                var oldSymbol = newRules[i].Original;
                                var sentence  = newRules[i].DirectDerivative.ToArray();
                                int n         = sentence.Length;
                                Debug.Assert(n < 3);

                                if (n == 1 && sentence[0] == nullable)
                                {
                                    AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty));
                                }
                                else if (n == 2)
                                {
                                    if (sentence[0] == sentence[1] && sentence[0] == nullable)
                                    {
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty));
                                    }
                                    else if (sentence[0] == nullable)
                                    {
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[1] })));
                                    }
                                    else
                                    {
                                        AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] })));
                                    }
                                }
                            }
                            newNonterminals.Remove(nullable);
                        }
                        newRules.Remove(rule);
                        toBeAddedRules = new List <Production>();
                        noEpsilonLeft  = false;
                        break;
                    }
                }
            }

            bool noUnitRuleLeft = false;

            while (!noUnitRuleLeft)
            {
                noUnitRuleLeft = true;
                foreach (var rule in newRules)
                {
                    bool isUnitRule = rule.DirectDerivative.Length == 1 && !rule.DirectDerivative.First().IsTerminal;
                    if (isUnitRule)
                    {
                        newRules.Remove(rule);

                        var toBeReplaced = rule.DirectDerivative.First();
                        var replacement  = rule.Original;
                        for (int i = 0; i < newRules.Count(); i++)
                        {
                            var oldSymbol = newRules[i].Original;
                            var sentence  = newRules[i].DirectDerivative.ToArray();

                            if (oldSymbol == toBeReplaced)
                            {
                                toBeAddedRules.Add(new Production(replacement, new Sentence(sentence)));
                            }
                        }
                        newNonterminals.Remove(toBeReplaced);
                        newRules.AddRange(toBeAddedRules);
                        toBeAddedRules = new List <Production>();

                        noUnitRuleLeft = false;
                        break;
                    }
                }
            }

            return(new ContextFreeGrammar(newNonterminals.ToArray(), this.terminals, newRules.ToArray(), newStarting));
        }