/// <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; }
/// <summary> /// Calculates and returns the read function on the given <paramref name="set"/>. /// </summary> /// <param name="set"></param> /// <param name="symbol"></param> /// <param name="grammar"><paramref name="set"/> and <paramref name="symbol"/> belong to this grammar.</param> /// <returns></returns> /// <exception cref="ArgumentNullException"> if any of the parameters is <c>null</c>.</exception> public static ISet<LR0Item> Read( ISet<LR0Item> set, Symbol symbol, RestrictedStartSymbolGrammar grammar ) { if( object.ReferenceEquals(set, null) ) throw new ArgumentNullException("set"); if( object.ReferenceEquals(symbol, null) ) throw new ArgumentNullException("symbol"); if( object.ReferenceEquals(grammar, null) ) throw new ArgumentNullException("grammar"); var result = new HashSet<LR0Item>(); foreach( var item in set ) if( item.CursorPosition < item.Rule.RightHandSide.Count && item.Rule.RightHandSide[item.CursorPosition].Equals(symbol) ) { // If the next symbol is the reading symbol, advance the CursorPosition // then add the closure of it to the result. var new_set = new HashSet<LR0Item>(); new_set.Add(new LR0Item(item.Rule, item.CursorPosition + 1)); result.UnionWith(Closure(new_set, grammar)); } return result; }
/// <summary> /// Calculates and returns the closure of the given canonical set. /// </summary> /// <param name="set">Get the closure of this set.</param> /// <param name="grammar">The set belongs to this grammar.</param> /// <returns>The closure of the given <paramref name="set"/>.</returns> /// <exception cref="ArgumentNullException"> if any of the parameters is <c>null</c>.</exception> public static ISet<LR0Item> Closure( ISet<LR0Item> set, RestrictedStartSymbolGrammar grammar ) { if( object.ReferenceEquals(set, null) ) throw new ArgumentNullException("set"); if( object.ReferenceEquals(grammar, null) ) throw new ArgumentNullException("grammar"); var closure = new List<LR0Item>(set); for( int i = 0; i < closure.Count; ++i ) { var item = closure[i]; // Skip this, if the cursor pos is on the end if( item.CursorPosition == item.Rule.RightHandSide.Count ) continue; // Skip this, if the next_symbol is not grammatical var next_symbol = item.Rule.RightHandSide[item.CursorPosition]; if( !(next_symbol is GrammaticalSymbol) ) continue; // Get all the rules whit next_symbol on the left hand side var rules = from rule in grammar.Rules where rule.LeftHandSide.Equals(next_symbol) select rule; // Add all the generated RL(0) items to the closure foreach( var rule in rules ) { var new_item = new LR0Item(rule, 0); if( !closure.Contains(new_item) ) closure.Add(new_item); } } return new HashSet<LR0Item>(closure); }