/// <summary> /// Creates and returns the LR(0) canonical sets for the given <paramref name="grammar"/>. /// </summary> /// <param name="grammar">The grammar to build the canonical sets for.</param> /// <returns>The built canonical sets.</returns> /// <exception cref="ArgumentNullException"> if <paramref name="grammar"/> is <c>null</c>.</exception> public static LR0CanonicalSets Build( RestrictedStartSymbolGrammar grammar ) { if( grammar == null ) throw new ArgumentNullException("grammar"); var terms_and_gramms = new List<Symbol>(); terms_and_gramms.AddRange(grammar.Grammaticals); terms_and_gramms.AddRange(grammar.Terminals); var sets = new LR0CanonicalSets(); // Calculate the I0 canonical set from the 'starting' rule var s0 = new HashSet<LR0Item>(); if( grammar.Rules.Count > 0 ) s0.Add(new LR0Item(grammar.StartRule, 0)); var I0 = Closure(s0, grammar); sets.Add(I0); // Generate LR0CanonicalSets with Read() for( int current_set_id = 0; current_set_id < sets.Sets.Count; ++current_set_id ) // Generate new sets for every symbol read foreach( var symbol in terms_and_gramms ) { var new_I = Read(sets.Sets[current_set_id], symbol, grammar); // If the set is empty then continue if( new_I.Count == 0 ) continue; // Identify new_I int next_set_id = sets.IndexOf(new_I); // If this is a new CanonicalSet then add to the group if( next_set_id == -1 ) next_set_id = sets.Add(new_I); // Record the state transition sets.SetTransition(current_set_id, symbol, next_set_id); } return sets; }