// generator is the non-terminal placed at the end of the chunk
        // such non-terminal generates what can follow it, which can contain also non-terminal at the end
        // which generates...
        // ...until we get the length of required lookahead count
        public FollowSets <SYMBOL_ENUM> ComputeFollowSets()
        {
            followSets = new FollowSets <SYMBOL_ENUM>(lookaheadWidth);

            // fill all symbols with initially empty follow set
            foreach (SYMBOL_ENUM symbol in nonTerminals.Concat(terminals))
            {
                followSets.Add(symbol, new SymbolChunkSet <SYMBOL_ENUM>());
            }

            followSets[startSymbol].Add(SymbolChunk.CreateRepeat(eofSymbol, lookaheadWidth));

            foreach (SYMBOL_ENUM symbol in nonTerminals.Concat(terminals))
            {
                bootstrapFromFirstSets(symbol);
            }

            // each chunk can have only terminals, or terminals + 1 non terminal at the end (as FollowSet tail generator)
            resolveFollowSetsDependencies();

            // removal of follow sets "generators"
            foreach (SymbolChunkSet <SYMBOL_ENUM> fset in followSets.Values)
            {
                fset.RemoveWhere(chunk => nonTerminals.Contains(chunk.Symbols.Last()));
            }

            return(followSets);
        }
        public HorizonSets <SYMBOL_ENUM> ComputeHorizonSets()
        {
            horizonSets = new HorizonSets <SYMBOL_ENUM>(lookaheadWidth);

            // fill all symbols with initially empty set
            foreach (SYMBOL_ENUM symbol in nonTerminals.Concat(terminals))
            {
                horizonSets.Add(symbol, new SymbolChunkSet <SYMBOL_ENUM>());
            }

            horizonSets[startSymbol].Add(SymbolChunk.CreateRepeat(eofSymbol, lookaheadWidth));

            foreach (SYMBOL_ENUM symbol in nonTerminals.Concat(terminals))
            {
                bootstrapFromFirstSets(symbol);
            }

            return(horizonSets);
        }