}         //method

        #endregion

        #region Creating parser states
        private void CreateInitialAndFinalStates()
        {
            //there is always just one initial production "Root' -> .Root", and we're interested in LR item at 0 index
            LR0ItemList itemList = new LR0ItemList();
            NtData      rootData = (NtData)Data.AugmentedRoot.ParserData;

            itemList.Add(rootData.Productions[0].LR0Items[0]);
            Data.InitialState = FindOrCreateState(itemList); //it is actually create
            Data.InitialState.Items[0].NewLookaheads.Add(Grammar.Eof.Key);
            #region comment about FinalState
            //Create final state - because of the way states construction works, it doesn't create the final state automatically.
            // We need to create it explicitly and assign it to _data.FinalState property
            // The final executed reduction is "Root' -> Root.". This jump is executed as follows:
            //   1. parser creates Root' node
            //   2. Parser pops the state from stack - that would be initial state
            //   3. Finally, parser tries to find the transition in state.Actions table by the key of [Root'] element.
            // We must create the final state, and create the entry in transition table
            // The final state is based on the same initial production, but different LRItem - the one with dot AFTER the root nonterminal.
            // it is item at index 1.
            #endregion
            itemList.Clear();
            itemList.Add(rootData.Productions[0].LR0Items[1]);
            Data.FinalState = FindOrCreateState(itemList); //it is actually create
            //Create shift transition from initial to final state
            string rootKey = Data.AugmentedRoot.Key;
            Data.InitialState.Actions[rootKey] = new ActionRecord(rootKey, ParserActionType.Shift, Data.FinalState, null);
        }
 private void InitNonTerminalData()
 {
     foreach (NonTerminal nt in Data.NonTerminals)
     {
         NtData.GetOrCreate(nt);
     }
 }
        private bool CalculateNullability(NonTerminal nonTerminal, NonTerminalList undecided)
        {
            NtData nonTerminalInfo = (NtData)nonTerminal.ParserData;

            foreach (Production prod in nonTerminalInfo.Productions)
            {
                //If production has terminals, it is not nullable and cannot contribute to nullability
                if (prod.IsSet(ProductionFlags.HasTerminals))
                {
                    continue;
                }
                if (prod.IsSet(ProductionFlags.IsEmpty))
                {
                    nonTerminalInfo.Nullable = true;
                    return(true); //Nullable
                }//if
                //Go thru all elements of production and check nullability
                bool allNullable = true;
                foreach (BnfTerm term in prod.RValues)
                {
                    NtData ntd = term.ParserData as NtData;
                    if (ntd != null)
                    {
                        allNullable &= ntd.Nullable;
                    }
                }//foreach nt
                if (allNullable)
                {
                    nonTerminalInfo.Nullable = true;
                    return(true);
                }
            }//foreach prod
            return(false); //cannot decide
        }
 private void CreateProductions()
 {
     Data.Productions.Clear();
     //each LR0Item gets its unique ID, last assigned (max) Id is kept in static field
     LR0Item._maxID = 0;
     foreach (NonTerminal nt in Data.NonTerminals)
     {
         NtData ntInfo = NtData.GetOrCreate(nt);
         ntInfo.Productions.Clear();
         //Get data (sequences) from both Rule and ErrorRule
         BnfExpressionData allData = new BnfExpressionData();
         allData.AddRange(nt.Rule.Data);
         if (nt.ErrorRule != null)
         {
             allData.AddRange(nt.ErrorRule.Data);
         }
         //actually create productions for each sequence
         foreach (BnfTermList prodOperands in allData)
         {
             Production prod = CreateProduction(nt, prodOperands);
             //Add the production to non-terminal's list and to global list
             ntInfo.Productions.Add(prod);
             Data.Productions.Add(prod);
         }//foreach prodOperands
     }
 }
        private void CalculateFirsts()
        {
            //1. Calculate PropagateTo lists and put initial terminals into Firsts lists
            foreach (Production prod in Data.Productions)
            {
                NtData lvData = prod.LValue.ParserData as NtData;
                foreach (BnfTerm term in prod.RValues)
                {
                    if (term is Terminal)            //it is terminal, so add it to Firsts and that's all with this production
                    {
                        lvData.Firsts.Add(term.Key); // Add terminal to Firsts (note: Add ignores repetitions)
                        break;                       //from foreach term
                    }//if
                    NtData ntInfo = term.ParserData as NtData;
                    if (!ntInfo.PropagateFirstsTo.Contains(prod.LValue))
                    {
                        ntInfo.PropagateFirstsTo.Add(prod.LValue); //ignores repetitions
                    }
                    if (!ntInfo.Nullable)
                    {
                        break;         //if not nullable we're done
                    }
                }//foreach oper
            }//foreach prod

            //2. Propagate all firsts thru all dependencies
            NonTerminalList workList = Data.NonTerminals;

            while (workList.Count > 0)
            {
                NonTerminalList newList = new NonTerminalList();
                foreach (NonTerminal nt in workList)
                {
                    NtData ntInfo = (NtData)nt.ParserData;
                    foreach (NonTerminal toNt in ntInfo.PropagateFirstsTo)
                    {
                        NtData toInfo = (NtData)toNt.ParserData;
                        foreach (string symbolKey in ntInfo.Firsts)
                        {
                            if (!toInfo.Firsts.Contains(symbolKey))
                            {
                                toInfo.Firsts.Add(symbolKey);
                                if (!newList.Contains(toNt))
                                {
                                    newList.Add(toNt);
                                }
                            } //if
                        }     //foreach symbolKey
                    }         //foreach toNt
                }             //foreach nt in workList
                workList = newList;
            }                 //while
        }                     //method
        //Creates closure items with "spontaneously generated" lookaheads
        private bool AddClosureItems(ParserState state)
        {
            bool result = false;

            //note that we change collection while we iterate thru it, so we have to use "for i" loop
            for (int i = 0; i < state.Items.Count; i++)
            {
                LRItem  item     = state.Items[i];
                BnfTerm currTerm = item.Core.Current;
                if (currTerm == null || !(currTerm is NonTerminal))
                {
                    continue;
                }
                //1. Add normal closure items
                NtData currInfo = (NtData)currTerm.ParserData;
                foreach (Production prod in currInfo.Productions)
                {
                    LR0Item core    = prod.LR0Items[0]; //item at zero index is the one that starts with dot
                    LRItem  newItem = TryFindItem(state, core);
                    if (newItem == null)
                    {
                        newItem = new LRItem(state, core);
                        state.Items.Add(newItem);
                        result = true;
                    }
                    #region Comments on lookaheads processing
                    // The general idea of generating ("spontaneously") the lookaheads is the following:
                    // Let's the original item be in the form
                    //   [A -> alpha . B beta , lset]
                    //     where <B> is a non-terminal and <lset> is a set of lookaheads,
                    //      <beta> is some string (B's tail in our terminology)
                    // Then the closure item on non-teminal B is an item
                    //   [B -> x, firsts(beta + lset)]
                    //      (the lookahead set is expression after the comma).
                    // To generate lookaheads on a closure item, we simply take "firsts"
                    //   from the tail <beta> of the NonTerminal <B>.
                    //   Normally if tail <beta> is nullable we would add ("propagate")
                    //   the <lset> lookaheads from <A> to <B>.
                    //   We dont' do it right here - we simply add a propagation link.
                    //   We propagate all lookaheads later in a separate process.
                    #endregion
                    newItem.NewLookaheads.AddRange(item.Core.TailFirsts);
                    if (item.Core.TailIsNullable && !item.PropagateTargets.Contains(newItem))
                    {
                        item.PropagateTargets.Add(newItem);
                    }
                } //foreach prod
            }     //for i (LRItem)
            return(result);
        }
        }                     //method

        #endregion

        #region Calculating Tail Firsts
        private void CalculateTailFirsts()
        {
            foreach (Production prod in Data.Productions)
            {
                StringSet accumulatedFirsts = new StringSet();
                bool      allNullable       = true;
                //We are going backwards in LR0Items list
                for (int i = prod.LR0Items.Count - 1; i >= 0; i--)
                {
                    LR0Item item = prod.LR0Items[i];
                    if (i >= prod.LR0Items.Count - 2)
                    {
                        //Last and before last items have empty tails
                        item.TailIsNullable = true;
                        item.TailFirsts.Clear();
                        continue;
                    }
                    BnfTerm nextTerm = prod.RValues[i + 1]; //Element after-after-dot; remember we're going in reverse direction
                    NtData  nextData = (NtData)nextTerm.ParserData;
                    //if (ntElem == null) continue; //it is not NonTerminal
                    bool notNullable = nextTerm is Terminal || nextData != null && !nextData.Nullable;
                    if (notNullable) //next term is not nullable  (a terminal or non-nullable NonTerminal)
                    //term is not nullable, so we clear all old firsts and add this term
                    {
                        accumulatedFirsts.Clear();
                        allNullable         = false;
                        item.TailIsNullable = false;
                        if (nextTerm is Terminal)
                        {
                            item.TailFirsts.Add(nextTerm.Key);//term is terminal so add its key
                            accumulatedFirsts.Add(nextTerm.Key);
                        }
                        else if (nextData != null)                     //it is NonTerminal
                        {
                            item.TailFirsts.AddRange(nextData.Firsts); //nonterminal
                            accumulatedFirsts.AddRange(nextData.Firsts);
                        }
                        continue;
                    }
                    //if we are here, then ntElem is a nullable NonTerminal. We add
                    accumulatedFirsts.AddRange(nextData.Firsts);
                    item.TailFirsts.AddRange(accumulatedFirsts);
                    item.TailIsNullable = allNullable;
                } //for i
            }     //foreach prod
        }         //method