private void ValidateNoUndeclaredNonterminal() { foreach (var item in Productions) { foreach (var nt in item.Body.Where(x => x is NonterminalSymbol).Cast <NonterminalSymbol>()) { if (!Productions.Any(x => x.Head == nt)) { throw new GrammarException(new Location(), $"símbolo {nt} não declarado"); } } } }
/// <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 }); }