Create <SYMBOL_ENUM, TREE_NODE>(Productions <SYMBOL_ENUM, TREE_NODE> productions,
                                        PrecedenceTable <SYMBOL_ENUM> precedenceTable,
                                        GrammarReport <SYMBOL_ENUM, TREE_NODE> report,
                                        int lookaheadWidth)

            where SYMBOL_ENUM : struct
            where TREE_NODE : class
        {
            ActionTable <SYMBOL_ENUM, TREE_NODE> action_table = CreateActionTable(productions, precedenceTable, report, lookaheadWidth);

            if (action_table == null)
            {
                return(null);
            }
            else
            {
                return(new Parser <SYMBOL_ENUM, TREE_NODE>(action_table, productions.SymbolsRep));
            }
        }
        public ActionTable <SYMBOL_ENUM, TREE_NODE> FillActionTable(Productions <SYMBOL_ENUM, TREE_NODE> productions,
                                                                    FirstSets <SYMBOL_ENUM> firstSets,
                                                                    CoverSets <SYMBOL_ENUM> coverSets,
                                                                    HorizonSets <SYMBOL_ENUM> horizonSets,
                                                                    int lookaheadWidth,
                                                                    Dfa <SYMBOL_ENUM, TREE_NODE> dfa,
                                                                    PrecedenceTable <SYMBOL_ENUM> precedenceTable,
                                                                    GrammarReport <SYMBOL_ENUM, TREE_NODE> report)
        {
            this.coverSets       = coverSets;
            this.horizonSets     = horizonSets;
            this.report          = report;
            this.precedenceTable = precedenceTable ?? new PrecedenceTable <SYMBOL_ENUM>(productions.SymbolsRep);
            this.symbolsRep      = productions.SymbolsRep;
            actionTable          = new ActionTable <SYMBOL_ENUM, TREE_NODE>(dfa, productions,
                                                                            lookaheadWidth);

            foreach (Node <SYMBOL_ENUM, TREE_NODE> node in dfa.Nodes)
            {
                foreach (SymbolChunk <SYMBOL_ENUM> chunk in node.State.PossibleInputs)
                {
                    ParseAction <SYMBOL_ENUM, TREE_NODE> action_data = computeAction(node, chunk);

                    if (!report.HasGrammarErrors)
                    {
                        actionTable.Add(node.State.Index, chunk, new[] { action_data });
                    }
                }

                // checking recovery conflicts

                IEnumerable <SingleState <SYMBOL_ENUM, TREE_NODE> > recovery_items = node.State.ParsingActiveItems
                                                                                     .Where(it => it.IsAtRecoveryPoint);

                var recovery_stats = DynamicDictionary.CreateWithDefault <SYMBOL_ENUM, List <SingleState <SYMBOL_ENUM, TREE_NODE> > >();
                foreach (SingleState <SYMBOL_ENUM, TREE_NODE> rec_state in recovery_items)
                {
                    foreach (SymbolChunk <SYMBOL_ENUM> first in firstSets[rec_state.RecoveryMarkerSymbol].Chunks)
                    {
                        recovery_stats[first.Symbols.First()].Add(rec_state);
                    }
                }

                foreach (var pair in recovery_stats.Where(it => it.Value.Count > 1))
                {
                    report.AddError(pair.Value.Select(it => it.IndexStr), "Recovery item conflict on \"" + symbolsRep.Get(pair.Key) + "\".");
                }
            }

            report.AddWarnings(precedenceTable.GetUnusedEntries(symbolsRep));

            if (report.HasGrammarErrors)
            {
                return(null);
            }
            else
            {
                report.ActionTable = actionTable;
                return(actionTable);
            }
        }