/// <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 }); }
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); }
/// <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)); }
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); }
/// <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); } } }
/// <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 }); }
/// <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()); }
protected GrammarElement(GrammarElement <T> other) { InnerValue = other.InnerValue; }