예제 #1
0
        /// <summary>
        ///     Gets a collection of Terminal elements that can appear after the element that is after the dot of the item.
        /// </summary>
        /// <example>
        ///     With Grammar:
        ///     S -> E
        ///     E -> T
        ///     E -> (E)
        ///     T -> n
        ///     T -> + T
        ///     T ->  T + n
        ///     Follow(S -> •E) : {$}
        ///     Follow(T -> •+ T) : {'+', 'n'}
        ///     Follow(T -> •n, ')') : {')'}
        /// </example>
        /// <param name="nonTerminal"></param>
        /// <returns></returns>
        public IEnumerable <Terminal <T> > Follow(LRItem <T> item)
        {
            //Follow(item) is First(b) where item is:
            //A -> a•Eb

            GrammarElement <T> element = item.GetNextElement(1);

            if (element != null)
            {
                //if(item.LookaheadElement != null && item.GetNextElement(2) == null)
                //{
                //    //if it is, then include the lookahead of item in the follow set.
                //    return First(element).Concat(new[] { item.LookaheadElement });
                //}
                ////If the element is not the last element in the production.
                //else
                //{
                return(First(element));
                //}
            }
            if (item.LookaheadElement == null)
            {
                return new[] { EndOfInputElement }
            }
            ;
            return(new[] { item.LookaheadElement });
        }
예제 #2
0
 public static GrammarElement <T>[] operator +(GrammarElement <T>[] left, GrammarElement <T> right)
 {
     GrammarElement <T>[] elements = new GrammarElement <T> [left.Length + 1];
     left.CopyTo(elements, 0);
     elements[elements.Length - 1] = right;
     return(elements);
 }
예제 #3
0
 /// <summary>
 ///     Gets the collection of terminal elements that can appear as the first element of the given element.
 ///     If element is a Terminal, then First(element) : {element}. Otherwise if element is a NonTerminal,
 ///     then First(element) : {set of first terminal elements matching the productions of element}.
 /// </summary>
 /// <example>
 ///     With Grammar:
 ///     E -> T
 ///     E -> ( E )
 ///     T -> n
 ///     T -> + T
 ///     T -> T + n
 ///     FIRST(E): {'n', '+', '('}
 ///     FIRST(T): {'n', '+'}
 /// </example>
 /// <param name="element"></param>
 /// <returns></returns>
 public IEnumerable <Terminal <T> > First(GrammarElement <T> element)
 {
     if (element is Terminal <T> )
     {
         return new[] { (Terminal <T>)element }
     }
     ;
     return(First((NonTerminal <T>)element));
 }
예제 #4
0
        public static GrammarElement <T>[] operator *(GrammarElement <T> left, int right)
        {
            if (right < 0)
            {
                throw new ArgumentOutOfRangeException("right", "Must be greater than or equal to 0.");
            }
            GrammarElement <T>[] elements = new GrammarElement <T> [right];

            for (int i = 0; i < right; i++)
            {
                elements[i] = left;
            }

            return(elements);
        }
예제 #5
0
        /// <summary>
        ///     Creates transitions from the given node to other nodes based on the items contained in the given node.
        /// </summary>
        /// <param name="startingNode"></param>
        private void CreateTransitions(StateNode <GrammarElement <T>, LRItem <T>[]> startingNode)
        {
            //List<IEnumerable<LRItem<T>>> existingSets = new List<IEnumerable<LRItem<T>>>(startingNode.FromTransitions.Select(a => a.Value.Value));

            LRItem <T>[] set = startingNode.Value;

            IEnumerable <GrammarElement <T> > nextElements = startingNode.Value.Select(a => a.GetNextElement()).Where(a => a != null).DistinctBy(a => a.ToString());

            foreach (GrammarElement <T> next in nextElements)
            {
                var state = new List <LRItem <T> >();
                state.AddRange(set.Where(a =>
                {
                    GrammarElement <T> e = a.GetNextElement();
                    if (e != null)
                    {
                        return(e.Equals(next));
                    }
                    return(false);
                }).Select(a => a.Copy()));

                state.ForEach(a => a.DotIndex++);

                //add the Closure
                LRItem <T>[] closure = state.Select(a => LR1Closure(a)).SelectMany(a => a).DistinctBy(a => a.ToString()).ToArray();

                state.AddRange(closure);

                //get an already existing transition
                StateNode <GrammarElement <T>, LRItem <T>[]> node = startingNode.Graph.Root.GetFromTransition(a => a.Value.SequenceEqual(state));

                if (node == null)
                {
                    if (startingNode.Value.SequenceEqual(state))
                    {
                        node = startingNode;
                        continue;
                    }
                    node = new StateNode <GrammarElement <T>, LRItem <T>[]>(state.ToArray(), startingNode.Graph);
                }
                if (!startingNode.FromTransitions.Any(a => a.Key.Equals(next)))
                {
                    //add the state transition
                    startingNode.AddTransition(next, node);
                    CreateTransitions(node);
                }
            }
        }
예제 #6
0
        /// <summary>
        ///     Gets a collection of Terminal elements that can appear after the element that is after the dot of the item.
        /// </summary>
        /// <example>
        ///     With Grammar:
        ///     S -> E
        ///     E -> T
        ///     E -> (E)
        ///     T -> n
        ///     T -> + T
        ///     T ->  T + n
        ///     Follow(S -> •E) : {$}
        ///     Follow(T -> •+ T) : {'+', 'n'}
        ///     Follow(T -> •n, ')') : {')'}
        /// </example>
        /// <param name="nonTerminal"></param>
        /// <returns></returns>
        private IEnumerable <Terminal <T> > Follow(LRItem <T> item, IEnumerable <LRItem <T> > totalItems)
        {
            //Follow(item) is First(b) where item is:
            //A -> a•Eb

            GrammarElement <T> element = item.GetNextElement(1);

            if (element != null)
            {
                if (element is NonTerminal <T> )
                {
                    var firstSet = new List <Terminal <T> >();

                    //if the element has a production with no derived elements and the element is at the end of the current item's production, then
                    //add the lookahead of the given item.

                    //if there is any production of the current element that has no derived elements
                    if (Productions.Any(a => a.NonTerminal.Equals(element) && a.DerivedElements.Count == 0))
                    {
                        //if the current element is the end of the current item's production
                        if (item.GetNextElement(2) == null)
                        {
                            firstSet.Add(item.LookaheadElement ?? EndOfInputElement);
                        }
                    }

                    //select the lookahead element or end of input element for each item in the previous set
                    //List<Terminal<T>> firstSet = new List<Terminal<T>>(items.Select(a => a.LookaheadElement == null ? EndOfInputElement : a.LookaheadElement));

                    //add the rest of the first set.
                    firstSet.AddRange(First(element));
                    return(firstSet);
                }
                return(First(element));
            }
            if (item.LookaheadElement == null)
            {
                return new[] { EndOfInputElement }
            }
            ;
            return(new[] { item.LookaheadElement });
        }
예제 #7
0
        /// <summary>
        ///     Gets the collection of terminal elements that can appear as the first element
        ///     after the dot in the given LR Item. If next element, named T, is a terminal, then First(item) = {T}
        /// </summary>
        /// <example>
        ///     With Grammar:
        ///     S -> A
        ///     A -> A + B
        ///     A -> a
        ///     B -> b
        ///     First(S -> •A): {'a'}
        ///     First(A -> •A + B): {'a'}
        ///     First(A -> A • + B): {'+'}
        ///     First(B -> b): {'b'}
        /// </example>
        /// <param name="item"></param>
        /// <returns></returns>
        public IEnumerable <Terminal <T> > First(LRItem <T> item)
        {
            //get the next element and evaluate if it is a terminal or non terminal
            GrammarElement <T> nextElement = item.GetNextElement();

            //if nextElement is a Terminal then return {T}
            if (nextElement is Terminal <T> )
            {
                return new[] { (Terminal <T>)nextElement }
            }
            ;
            //otherwise find all of the productions that have nextElement on the LHS.
            Production <T> production = Productions.First(p => p.NonTerminal == item.LeftHandSide && p.DerivedElements.SequenceEqual(item.ProductionElements));

            var firstElements = new List <Terminal <T> >();

            if (production.DerivedElements.Count > 0)
            {
                if (!production.DerivedElements[item.DotIndex].Equals(production.NonTerminal))
                {
                    GrammarElement <T> productionItem = production.GetElement(item.DotIndex);
                    if (productionItem != null)
                    {
                        //if it is a Terminal add to first elements
                        if (productionItem is Terminal <T> )
                        {
                            firstElements.Add((Terminal <T>)productionItem);
                        }
                        //otherwise add First(new LRItem(production)) of all of the productions where the LHS == productionItem
                        else
                        {
                            foreach (LRItem <T> i in Productions.Where(p => p.NonTerminal.Equals(productionItem)).Select(p => new LRItem <T>(0, p)))
                            {
                                firstElements.AddRange(First(i));
                            }
                        }
                    }
                }
            }
            return(firstElements.Distinct());
        }
예제 #8
0
 protected GrammarElement(GrammarElement <T> other)
 {
     InnerValue = other.InnerValue;
 }