예제 #1
0
        private static Dictionary <Nonterminal, Set <Terminal <TTokenKind> > > ComputeFollow(
            Grammar <TTokenKind, TNonterminal> grammar,
            IFirstSymbolsAnalyzer <TTokenKind> analyzer)
        {
            var(initFollowSets, graph) = DigraphAlgorithm.GetFollowGraph(grammar, analyzer);

            var followSets = DigraphAlgorithm.Traverse(graph, initFollowSets);

            var followMap = grammar.Nonterminals.ToDictionary(v => v, v => followSets[v.Index]);

            return(followMap);
        }
        // TODO: Insert into symbols overload
        // FIRST can be thought of as the extension of START, but often FIRST is defined for both single symbols
        // and sentential forms. That is FIRST is extended to all grammar symbols (i.e. sentential forms)
        // The FIRST function is a simple extension of START (single symbol) to the domain of sentential forms.
        //      FIRST(α) = { x ∈ T | α ∗⇒ xβ }
        // An alternative definition which shows how to derive FIRST from START recursively is
        //      FIRST(X1X2...Xk) = START(X1) ∪ FIRST(X2...Xk), if X1 is nullable
        //      FIRST(X1X2...Xk) = START(X1)                    otherwise
        //      FIRST(ε) = Ø = { }

        /// <summary>
        /// The First function yields the set of starter symbols for a sequence of grammar symbols. It is formally
        /// defined as
        ///      FIRST(α) = { a ∈ T | α ∗⇒ aβ }
        /// for any sentential form α ∈ (T ∪ N)*. We have therefore extended the set-valued function to all sentential forms.
        /// </summary>
        /// <param name="analyzer"></param>
        /// <param name="symbols">The sequence of symbols (possibly empty, aka epsilon)</param>
        public static IReadOnlySet <Terminal <TTokenKind> > First <TTokenKind>(
            this IFirstSymbolsAnalyzer <TTokenKind> analyzer,
            IEnumerable <Symbol> symbols) where TTokenKind : struct, Enum
        {
            // If α is any string of grammar symbols, let First(α) be the set of terminals that begin the
            // strings derived from α. In some texts (dragon book) if α *=> ε, then ε is also in First(α).
            // We prefer to keep nullable in a separate Erasable function.
            var first = new Set <Terminal <TTokenKind> >();

            foreach (var symbol in symbols)
            {
                first.AddRange(analyzer.First(symbol));
                if (!analyzer.Erasable(symbol))
                {
                    break;
                }
            }
            return(first);
        }