protected virtual void PopulateNextCache()
 {
     for (int i = 0; i < TargetGrammar.Count; i++)
     {
         var r = initialListing[TargetGrammar[i]];
         for (int j = 0; j < r.Count; j++)
         {
             AdvanceableProduction prod = r[j];
             while (prod.HasNext)
             {
                 var tmp = prod.FunctionalNext();
                 advancementDict[prod] = tmp;
                 prod = tmp;
             }
             advancementDict[prod] = prod;
             terminates[prod]      = new AdvanceableRule(r.Name);
             terminates[prod].Add(prod);
         }
     }
 }
		private string ToString0(AdvanceableProduction production)
		{
			StringBuilder sb = new StringBuilder();
			sb.AppendFormat("[{0} => ",Name);
			for(int i = 0;i < production.Min; i++)
				sb.AppendFormat("{0} ", production[i]);	
			sb.Append("!");
			for(int i = production.Min;i < production.Position; i++)
				sb.AppendFormat("{0} ", production[i]);
			sb.Append("@");
			for(int i = production.Position; i < production.Max; i++)
				sb.AppendFormat("{0} ", production[i]);
			sb.AppendFormat(", {0}]", LookaheadSymbol);
			return sb.ToString();
		}
        public override IEnumerable <LookaheadRule> Closure(
            IEnumerable <LookaheadRule> rules,
            string terminateSymbol)
        {
            //Closure is more refined.
            //If [A → α • B β, a] belongs to the set of items,
            //and B → γ is a production of the grammar,
            //then we add the item [B → • γ, b] for all b in FIRST(β a).
            HashSet <LookaheadRule> rr = new HashSet <LookaheadRule>(rules);
            int size = currentRules.Count;

            do
            {
                size = rr.Count;
                //get rid of the
                foreach (var rule in rr)
                {
                    var a         = rule.LookaheadSymbol;
                    var container = singles[rule.Name][rule.LookaheadSymbol];
                    for (int j = 0; j < rule.Count; j++)
                    {
                        var    p      = rule[j];
                        string symbol = p.Current;
                        if (!p.HasNext)
                        {
                            nullTerminators.Add(terminates[p]);
                        }
                        else
                        {
                            if (TargetGrammar.Exists(symbol))
                            {
                                AdvanceableProduction betaProd = advancementDict[p];      //create beta
                                var target       = initialListing[TargetGrammar[symbol]]; //grab the B-Production
                                var actualTarget = memo[target];
                                if (!betaProd.HasNext && a.Equals(terminateSymbol))
                                {
                                    currentRules.Add(actualTarget[terminateSymbol]);
                                }
                                else
                                {
                                    if (betaProd.HasNext)
                                    {
                                        var next = container[p];

                                        var ff = First(next, betaProd.Position);
                                        foreach (var v in ff)
                                        {
                                            currentRules.Add(actualTarget[v]);
                                        }
                                    }
                                    currentRules.Add(actualTarget[a]);
                                }
                            }
                        }
                    }
                }
                rr.UnionWith(currentRules);
                currentRules.Clear();
            }while(rr.Count != size);
            for (int n = 0; n < nullTerminators.Count; n++)
            {
                var    v    = nullTerminators[n];
                string name = v.Name;
                foreach (var s in rr)
                {
                    if (s.Name.Equals(name))
                    {
                        foreach (var qq in v)
                        {
                            if (!s.Contains(qq))
                            {
                                s.Add(qq);
                            }
                        }
                    }
                }
            }
            if (nullTerminators.Count > 0)
            {
                nullTerminators.Clear();
            }
            if (currentRules.Count > 0)
            {
                currentRules.Clear();
            }
            return(rr);
        }