public BottomUpParser(LexicalAnalyzer lexicalAnalyzer)
        {
            LexicalAnalyzer = lexicalAnalyzer;

            GenerateAutomaton();

            ParsingTable = new ParsingTable(CanonicalSets, GrammarSymbols, Shift, Accept, Reduce);
        }
        private ActionParsingTableEntry GetEntry()
        {
            List <ActionParsingTableEntry> entries = ParsingTable.GetSegment(Stack.Last()).Entries
                                                     .Where(x => x is ActionParsingTableEntry a &&
                                                            a.ExpressionDefinition.TokenType == Current.Type).Cast <ActionParsingTableEntry>().ToList();

            if (entries.Count == 1)
            {
                return(entries.First());
            }
            else if (entries.Count > 1)
            {
                // reduce/reduce of shift/reduce conflict

                List <ActionParsingTableEntry> entriesForLookahead = entries.Where(x => x.Items.Any(y => y.Lookahead.Any(z => z.TokenType == Current.Type))).ToList();;

                if (entriesForLookahead.Count == 1)
                {
                    return(entriesForLookahead.First());
                }

                if (entries.Count == 1)
                {
                    return(entries.First());
                }
                else if (entries.Count > 1)
                {
                    return(ResolveShiftReduceConflicts(entries));
                }
                else
                {
                    Error();
                }
            }
            else
            {
                Error();
            }

            return(null);
        }
        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);
        }