public bool CoreEquals(Lr1ItemSet <T> other) { // Must be the same number of items if (Items.Count == other.Items.Count) { // Every item must have the same production rule the dot at the same place return(Items.All(f => other.Any(o => o.ProductionRule == f.ProductionRule && f.DotLocation == o.DotLocation))); } return(false); }
internal IParser <T> CreateParser() { // First order of business is to create the canonical list of LR1 states, or at least we are going to go through // them as we merge the sets together. // This starts with augmenting the grammar with an accept symbol, then we derive the // grammar from that IProductionRule <T> start = grammar.Start; // Get the first and follow sets for all nonterminal symbols ISet <NonTerminal <T> > nullable = CalculateNullable(); TerminalSet <T> first = CalculateFirst(nullable); // So, we are going to calculate the LR1 closure for the start symbol, which should // be the augmented accept state of the grammar. // The closure is all states which are accessible by the dot at the left hand side of the // item. List <Lr1ItemSet <T> > itemSets = new List <Lr1ItemSet <T> > { Closure(new List <Lr1Item <T> > { new Lr1Item <T>(start, 0, new HashSet <Terminal <T> > { grammar.EndOfInputTerminal }) }, first, nullable) }; List <GotoSetTransition> gotoSetTransitions = new List <GotoSetTransition>(); // Repeat until nothing gets added any more // This is neccessary since we are merging sets as we go, which changes things around. bool added; do { added = false; for (int i = 0; i < itemSets.Count; ++i) { Lr1ItemSet <T> itemSet = itemSets[i]; foreach (ISymbol <T> symbol in grammar.AllSymbols) { // Calculate the itemset for by goto for each symbol in the grammar Lr1ItemSet <T> gotoSet = Goto(itemSet, symbol); // If there is anything found in the set if (gotoSet.Any()) { // Do a closure on the goto set and see if it's already present in the sets of items that we have // if that is not the case add it to the item set gotoSet = Closure(gotoSet, first, nullable); Lr1ItemSet <T> oldGotoSet = itemSets.Find(f => f.CoreEquals(gotoSet)); if (oldGotoSet == null) { // Add goto set to itemsets itemSets.Add(gotoSet); // Add a transition gotoSetTransitions.Add(new GotoSetTransition { From = itemSet, OnSymbol = symbol, To = gotoSet }); added = true; } else { // Already found the set // Merge the lookaheads for all rules oldGotoSet.MergeLookaheads(gotoSet); // Add a transition if it already isn't there GotoSetTransition nt = new GotoSetTransition { From = itemSet, OnSymbol = symbol, To = oldGotoSet }; if (!gotoSetTransitions.Any(a => (a.From == nt.From) && (a.OnSymbol == nt.OnSymbol) && (a.To == nt.To))) { gotoSetTransitions.Add(nt); } } } } } } while (added); LRParseTable <T> parseTable = CreateParseTable(itemSets, gotoSetTransitions); // Create a new parser using that parse table and some additional information that needs // to be available for the runtime parsing to work. return(new LRParser <T>( parseTable, (grammar.ErrorToken as Terminal <T>).TokenNumber, grammar.EndOfInputTerminal.TokenNumber, grammar.AllSymbols.OfType <Terminal <T> >().Select(f => f.DebugName).ToArray() )); }