public void UnregisterUse(ISymbolPrecedence <SYMBOL_ENUM> entry)
        {
            if (entry == null)
            {
                return;
            }

            List <int> use_counts = entryUseCounters[entry];

            if (use_counts.Last() > 0)
            {
                --use_counts[use_counts.Count - 1];
            }
        }
        GetShiftReduce(IEnumerable <SYMBOL_ENUM> shiftLhs, SYMBOL_ENUM reduceLhs,
                       IEnumerable <SYMBOL_ENUM> readSymbols, SymbolChunk <SYMBOL_ENUM> input,
                       Action <string> errorReporter)
        {
            ISymbolPrecedence <SYMBOL_ENUM> pattern = findShiftReducePattern(shiftLhs, reduceLhs, readSymbols, input, errorReporter);
            ISymbolPrecedence <SYMBOL_ENUM> oper    = findReduceOperator(readSymbols);

            if (oper == null || (pattern != null && oper.Priority < pattern.Priority))
            {
                return(registerUse(pattern));
            }
            else
            {
                return(registerUse(oper));
            }
        }
        private ISymbolPrecedence <SYMBOL_ENUM> registerUse(ISymbolPrecedence <SYMBOL_ENUM> entry)
        {
            if (entry == null)
            {
                return(null);
            }

            List <int> use_counts;

            if (!entryUseCounters.TryGetValue(entry, out use_counts))
            {
                use_counts = new List <int>();
                entryUseCounters.Add(entry, use_counts);
            }
            use_counts.Add(1);

            return(entry);
        }
        private ParseAction <SYMBOL_ENUM, TREE_NODE> computeAction(Node <SYMBOL_ENUM, TREE_NODE> node,
                                                                   SymbolChunk <SYMBOL_ENUM> inputChunk)
        {
            List <SingleState <SYMBOL_ENUM, TREE_NODE> > shift_items, reduce_items;

            NodeUtilities.FilterItems(node, inputChunk, out shift_items, out reduce_items);

            var rr_actions = reduce_items.Select(it => ReductionActionFactory.Create(it, coverSets, horizonSets)).ToArray();

            ISymbolPrecedence <SYMBOL_ENUM> rr_precedence = null;

            if (reduce_items.Count > 1)
            {
                if (!disambiguateReduceReduceConflictOnShortHorizon(rr_actions))
                {
                    rr_precedence = precedenceTable.GetReduceReduce(reduce_items.Select(it => it.LhsSymbol), inputChunk);

                    if (rr_precedence == null)
                    {
                        report.AddError(reduce_items.Select(it => it.IndexStr), "REDUCE/REDUCE conflict for input: " + inputChunk.ToString(symbolsRep));
                        rr_actions = null;
                    }
                }
            }


            // this is what will be the result of the function, it is crucial, that resolving RR conflict
            // should not collide with resolving RS conflict
            ParseAction <SYMBOL_ENUM, TREE_NODE> result_action = null;

            if (shift_items.Count == 0)
            {
                if (reduce_items.Count == 0)
                {
                    throw new Exception("Internal parser error -- wrong input for node " + node.State.Index + " for input: " + inputChunk.ToString(symbolsRep));
                }
                else if (reduce_items.Count == 1)
                {
                    result_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(false, rr_actions.Single().DisableHorizon());
                }
                else
                {
                    result_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(false, rr_actions);
                }
            }
            else if (reduce_items.Count == 0)
            {
                result_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(true);
            }
            else
            {
                if (rr_actions != null && disambiguateShiftReduceConflictOnHorizon(shift_items, rr_actions))
                {
                    result_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(true, rr_actions);
                }
                else
                {
                    // here we have not only some shift rules active, but also at least one reduce rule
                    // so it can be shift-reduce conflict or shift-reduce-reduce conflict

                    // we loop over reduce items, however this is becase we try to report ALL conflicts in one go
                    // in situation of no reduce/reduce conflict this would be a single or no item
                    foreach (SingleState <SYMBOL_ENUM, TREE_NODE> r_item in reduce_items)
                    {
                        // don't cache it because of usage registration
                        ISymbolPrecedence <SYMBOL_ENUM> shift_precedence = precedenceTable.GetShiftOperator(inputChunk);

                        // it picks up basic operator or entire pattern
                        ISymbolPrecedence <SYMBOL_ENUM> reduce_precedence = precedenceTable.GetShiftReduce(
                            shift_items.Select(s_item => s_item.LhsSymbol),
                            r_item.LhsSymbol,
                            r_item.RhsSeenSymbols,
                            inputChunk,
                            (s) => report.AddError(s)
                            );


                        // in operator mode we can copy from shift to reduce
                        if (reduce_precedence == null && shift_precedence != null && shift_precedence.Mode == SymbolPrecedence.ModeEnum.BasicOperatorSearch)
                        {
                            reduce_precedence = shift_precedence;
                        }

                        // if priority permits in shift-reduce mode we can copy from reduce to shift
                        if (reduce_precedence != null && reduce_precedence.Mode == SymbolPrecedence.ModeEnum.ShiftReduceConflict &&
                            (shift_precedence == null || reduce_precedence.Priority > shift_precedence.Priority))
                        {
                            precedenceTable.UnregisterUse(shift_precedence);
                            shift_precedence = reduce_precedence;
                        }

                        // we have to check if this is not killed by reduce-reduce priority meaning
                        // it would be reduce anyway
                        if (rr_precedence != null &&
                            (shift_precedence != null && rr_precedence.Priority > shift_precedence.Priority && shift_precedence.Mode == SymbolPrecedence.ModeEnum.ShiftReduceConflict) &&
                            (reduce_precedence == null || rr_precedence.Priority > reduce_precedence.Priority))
                        {
                            precedenceTable.UnregisterUse(shift_precedence);
                            precedenceTable.UnregisterUse(reduce_precedence);

                            continue;
                        }


                        ParseAction <SYMBOL_ENUM, TREE_NODE> local_action = null;

                        if (shift_precedence != null && reduce_precedence != null)
                        {
                            if (shift_precedence.Mode != reduce_precedence.Mode)
                            {
                                // the modes have to match
                            }
                            else if (reduce_precedence.Priority > shift_precedence.Priority)
                            {
                                local_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(false, Parser.ReductionAction.Create(r_item.CreateCell()));
                            }
                            else if (reduce_precedence.Priority < shift_precedence.Priority)
                            {
                                local_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(true);
                            }
                            else if (reduce_precedence.Associativity == AssociativityEnum.Reduce &&
                                     shift_precedence.Associativity == AssociativityEnum.Reduce)
                            {
                                local_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(false, Parser.ReductionAction.Create(r_item.CreateCell()));
                            }
                            else if (reduce_precedence.Associativity == AssociativityEnum.Shift &&
                                     shift_precedence.Associativity == AssociativityEnum.Shift)
                            {
                                local_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(true);
                            }
                            else if (reduce_precedence.Associativity == AssociativityEnum.Try &&
                                     shift_precedence.Associativity == AssociativityEnum.Try &&
                                     shift_precedence.Symbols.Equals(reduce_precedence.Symbols))
                            {
                                local_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(true, Parser.ReductionAction.Create(r_item.CreateCell()));
                            }
                            else if (reduce_precedence.Associativity == AssociativityEnum.None &&
                                     shift_precedence.Associativity == AssociativityEnum.None)
                            {
                                // it should trigger syntax error while parsing, it is not grammar error,
                                // so don't report it, but don't add to table either
                                local_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(false);
                                report.AddInformation("None precedence on (" + inputChunk.ToString(symbolsRep) + ") nulled out: " + String.Join(" ; ", shift_items.Select(it => it.Production.ToString())) + " vs. "
                                                      + r_item.Production.ToString());
                            }
                        }


                        // those cases should be solved at the grammar design stage
                        if (local_action == null // we didn't get any action
                            // we got some action but the current pack is different from the last one
                            || (result_action != null &&
                                (result_action.Shift != local_action.Shift ||
                                 result_action.HasAnyReduction != local_action.HasAnyReduction)))
                        {
                            report.AddError(shift_items.Select(it => it.IndexStr).Concat(r_item.IndexStr),
                                            "Reduce/shift conflict on symbol " + inputChunk.ToString(symbolsRep)
                                            + (local_action == null ? "" : " because of previous reduce/shift resolution")
                                            + ".");

                            precedenceTable.UnregisterUse(shift_precedence);
                            precedenceTable.UnregisterUse(reduce_precedence);
                            local_action = null;
                        }

                        if (local_action != null)
                        {
                            if (result_action == null)
                            {
                                result_action = local_action;
                            }
                            else
                            {
                                result_action = new ParseAction <SYMBOL_ENUM, TREE_NODE>(result_action.Shift && local_action.Shift,
                                                                                         result_action.Reductions.Concat(local_action.Reductions).ToArray());
                            }
                        }
                    } // end of iterating over reduce items

                    // we have rule for RR conflict and yet at the same time we have rule for RS conflict
                    // which overrides the first one -- so the RR rule should not exist in the first place
                    if (rr_actions != null && rr_actions.Length > 1 && result_action != null && !result_action.HasAnyReduction)
                    {
                        report.AddError(shift_items.Select(it => it.IndexStr),
                                        "Reduce/shift conflict resolution on symbol " + inputChunk.ToString(symbolsRep)
                                        + " overrides previous reduce/reduce resolution.");

                        precedenceTable.UnregisterUse(rr_precedence);
                        result_action = null;
                    }
                }
            }

            return(result_action);
        }