예제 #1
0
 /// <summary>
 ///     Creates a new LRItem with the given dot index from the given other item.
 /// </summary>
 /// <param name="dotIndex"></param>
 /// <param name="otherItem"></param>
 public LRItem(int dotIndex, LRItem <T> otherItem)
 {
     LeftHandSide       = otherItem.LeftHandSide;
     ProductionElements = otherItem.ProductionElements;
     DotIndex           = dotIndex;
     LookaheadElement   = otherItem.LookaheadElement;
 }
예제 #2
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 });
        }
예제 #3
0
 /// <summary>
 ///     Returns whether the value(s) contained by the given other LRItem equals this object.
 /// </summary>
 /// <param name="other"></param>
 /// <returns></returns>
 public bool Equals(LRItem <T> other)
 {
     if (LookaheadElement != null &&
         other.LookaheadElement != null)
     {
         return(LeftHandSide.Equals(other.LeftHandSide) && DotIndex == other.DotIndex && ProductionElements.SequenceEqual(other.ProductionElements) && LookaheadElement.Equals(other.LookaheadElement));
     }
     return(LeftHandSide.Equals(other.LeftHandSide) && DotIndex == other.DotIndex && ProductionElements.SequenceEqual(other.ProductionElements));
 }
예제 #4
0
        /// <summary>
        ///     Gets the LR(1) Closure of the given item.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public IEnumerable <LRItem <T> > LR1Closure(LRItem <T> item)
        {
            if (closures.ContainsKey(item))
            {
                return(closures[item]);
            }
            IEnumerable <LRItem <T> > closure = Lr1Closure(item, new HashSet <LRItem <T> >());

            closures.Add(item, closure);
            return(closure);
        }
예제 #5
0
        /// <summary>
        ///     Creates the first state.
        /// </summary>
        /// <returns></returns>
        public IEnumerable <LRItem <T> > CreateFirstState()
        {
            //get the starting item, S' -> S, $
            var startingItem = new LRItem <T>(0, Productions[0], EndOfInputElement);

            var firstState = new List <LRItem <T> >();

            //add S' -> S, $ to the first state
            firstState.Add(startingItem);

            //get the rest of the first state
            firstState.AddRange(Lr1Closure(startingItem, new HashSet <LRItem <T> >()));
            return(firstState);
        }
예제 #6
0
        /// <summary>
        ///     Gets the LR(1) Closure of the given item, using currentItems to filter out duplicates.
        /// </summary>
        /// <param name="item"></param>
        /// <param name="currentItems"></param>
        /// <returns></returns>
        private IEnumerable <LRItem <T> > Lr1Closure(LRItem <T> item, HashSet <LRItem <T> > currentItems)
        {
            //<LRItem<T>> items;

            //items = new List<LRItem<T>>();

            //add the current items
            //if (currentItems != null)
            //{
            //    items.AddRange(currentItems);
            //}

            GrammarElement <T> nextElement;

            //if the next element is a non terminal
            if ((nextElement = item.GetNextElement()) is NonTerminal <T> )
            {
                //get all of the productions whose LHS equals the next element
                IEnumerable <Production <T> > productions = Productions.Where(a => a.NonTerminal.Equals(nextElement));

                //for each of the possible following elements of item
                foreach (Terminal <T> l in Follow(item, currentItems))
                {
                    foreach (Production <T> p in productions)
                    {
                        //create a new item from the production
                        var newItem = new LRItem <T>(0, p);

                        //with a lookahead element of l from Follow(item)
                        newItem.LookaheadElement = l;

                        //if the item is not already contained
                        if (currentItems.Add(newItem))
                        {
                            //add the new item(but make sure it is not a duplicate
                            //items.Add(newItem);
                            //add the LR1 Closure of the new item
                            Lr1Closure(newItem, currentItems);
                        }
                    }
                }
            }
            return(currentItems.Distinct());
        }
예제 #7
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 });
        }
예제 #8
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());
        }
예제 #9
0
        /// <summary>
        ///     Gets a collection of LR(0) items that can be derived from the given item.
        /// </summary>
        /// <param name="item"></param>
        /// <param name="currentItems"></param>
        /// <returns></returns>
        private IEnumerable <LRItem <T> > Closure(LRItem <T> item, IEnumerable <LRItem <T> > currentItems)
        {
            List <LRItem <T> > items;

            items = new List <LRItem <T> >();

            if (currentItems == null)
            {
                items.Add(item);
            }

            //if the next item is a non terminal, get all of the productions of that non terminal
            if (item.GetNextElement() is NonTerminal <T> )
            {
                IEnumerable <Production <T> > productions = Productions.Where(a => a.NonTerminal.Equals(item.GetNextElement()));

                //remove duplicate productions
                if (currentItems != null)
                {
                    productions = productions.Where(a => !currentItems.Any(i => i.LeftHandSide.Equals(a.NonTerminal)));
                }


                //add the productions as LRItems
                items.AddRange(productions.Select(a => new LRItem <T>(0, a)));

                //add the Closure of each found production
                foreach (Production <T> p in productions)
                {
                    if (p.DerivedElements[0] is NonTerminal <T> )
                    {
                        items.AddRange(Closure(new LRItem <T>(0, p), items));
                    }
                }
            }

            return(items.Distinct());
        }
예제 #10
0
 /// <summary>
 ///     Gets a collection of LR(0) items that can be derived from the given item.
 /// </summary>
 /// <param name="item"></param>
 /// <param name="currentItems"></param>
 /// <returns></returns>
 public IEnumerable <LRItem <T> > Closure(LRItem <T> item)
 {
     return(Closure(item, null));
 }