private bool Shift(ActionParsingTableEntry entry)
        {
            ItemSet arg1 = entry.ItemSet;
            ExpressionDefinition arg3 = entry.ExpressionDefinition;

            List <ItemSet> transitions = arg1.Transitions.Where(x => x.Key.IsEqualTo(arg3)).Select(x => x.Value).ToList();

            if (transitions.Count > 1)
            {
                throw new Exception();
            }

            ItemSet transition = transitions.First();

            if (DebugModeEnabled)
            {
                Console.WriteLine("SHIFT " + Current.ToString() + ", to" + transition.Id);
            }
            Stack.Add(transition);

            ParsingNode parsingNode = new ParsingNode()
            {
                Expression = new TerminalExpression
                {
                    TokenType = ((TerminalExpressionDefinition)arg3).TokenType,
                    Key       = ((TerminalExpressionDefinition)arg3).Key
                },
                Parser        = this,
                SubProduction = arg3.SubProduction
            };

            parsingNode.Attributes.Add(ParserConstants.Token, Current);

            ParsingNodes.Add(parsingNode);

            Current = LexicalAnalyzer.GetNextToken();

            return(true);
        }
        private bool Reduce(ActionParsingTableEntry entry)
        {
            SubProduction subProduction = null;

            if (entry.Items.Count > 1)
            {
                Item match = entry.Items.First(x => x.Lookahead.Any(x => x.TokenType == Current.Type));
                subProduction = match.SubProduction;
            }
            else
            {
                subProduction = entry.Items.First().SubProduction;
            }

            NonTerminalExpressionDefinition target = new NonTerminalExpressionDefinition {
                Identifier = subProduction.Production.Identifier
            };

            ParsingNode parsingNode = new ParsingNode()
            {
                Expression = new NonTerminalExpression
                {
                    Identifier = subProduction.Production.Identifier,
                },
                Parser        = this,
                SubProduction = subProduction
            };

            for (int y = subProduction.Count - 1; y >= 0; y--)
            {
                for (int i = ParsingNodes.Count - 1; i >= 0; i--)
                {
                    if (ParsingNodes[i].Parent != null)
                    {
                        continue;
                    }

                    if (ParsingNodes[i].Expression is NonTerminalExpression ne &&
                        subProduction[y] is NonTerminalExpressionDefinition ned)
                    {
                        if (ne.Identifier == ned.Identifier)
                        {
                            ParsingNodes[i].Expression.Key = ned.Key;
                            ParsingNodes[i].Parent         = parsingNode;
                            break;
                        }
                    }
                    if (ParsingNodes[i].Expression is TerminalExpression te &&
                        subProduction[y] is TerminalExpressionDefinition ted)
                    {
                        if (te.TokenType == ted.TokenType)
                        {
                            ParsingNodes[i].Parent = parsingNode;
                            break;
                        }
                    }
                }
            }

            ParsingNodes.Add(parsingNode);

            List <ExpressionDefinition> expressionDefinitionsToRemove = subProduction.Where(x => !(x is SemanticActionDefinition) && !(x is TerminalExpressionDefinition ted && ted.TokenType == TokenType.EmptyString)).ToList();

            for (int i = 0; i < expressionDefinitionsToRemove.Count(); i++)
            {
                Stack.RemoveAt(Stack.Count - 1);
            }

            ItemSet tos = Stack.Last();
            List <ParsingTableEntry> entries = ParsingTable.GetSegment(tos).Entries
                                               .Where(x => x is GotoParsingTableEntry g &&
                                                      g.ItemSet == tos &&
                                                      g.ExpressionDefinition.IsEqualTo(target)).ToList();

            if (entries.Count > 1)
            {
                throw new Exception();
            }

            GotoParsingTableEntry gotoEntry = (GotoParsingTableEntry)entries.First();

            if (DebugModeEnabled)
            {
                Console.WriteLine("REDUCE DEST " + gotoEntry.Destination.Id + ", TARGET " + target.ToString());
            }
            Stack.Add(gotoEntry.Destination);

            return(true);
        }