public void BuildWithValidGrammar( RestrictedStartSymbolGrammar grammar, LR0CanonicalSets expected ) { var actual = LR0CanonicalSets.Build(grammar); Assert.NotNull(actual); Assert.True(actual.Equals(expected)); }
/// <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> /// Builds and return an SLR(1) <see cref="ParserTable"/> based on the given paramaters. /// </summary> /// <param name="grammar">The grammar.</param> /// <param name="canonical_sets">LR(0) canonical sets generated from the <paramref name="grammar"/>.</param> /// <param name="follow_sets">Follow sets of all the <paramref name="grammar"/>'s grammaticals /// (see <see cref="FollowSets"/>).</param> /// <returns>An SLR(1) parser table.</returns> public static ParserTable Build( ExtendedGrammar grammar, LR0CanonicalSets canonical_sets, IDictionary<GrammaticalSymbol, ISet<TerminalSymbol>> follow_sets) { if( object.ReferenceEquals(grammar, null) ) throw new ArgumentNullException("grammar"); if( object.ReferenceEquals(canonical_sets, null) ) throw new ArgumentNullException("canonical_sets"); if( object.ReferenceEquals(follow_sets, null) ) throw new ArgumentNullException("follow_sets"); var table = new ParserTable(canonical_sets.Sets.Count, grammar.Terminals.Count, grammar.Grammaticals.Count); for( int state_index = 0; state_index < canonical_sets.Sets.Count; ++state_index ) { // Steps foreach( var term in grammar.Terminals ) { int next_state_index = canonical_sets.GetTransition(state_index, term); if( next_state_index != -1 ) { if( table.GetAction(state_index, grammar.IndexOf(term)).Type != ParserTable.ActionType.Error ) throw new ArgumentException("Grammar is not SLR(1)."); //TODO: custom exception with conflict info table.SetAction(state_index, grammar.IndexOf(term), ParserTable.Action.Step(next_state_index)); } } // Gotos foreach( var gram in grammar.Grammaticals ) { int next_state_index = canonical_sets.GetTransition(state_index, gram); if( next_state_index != -1 ) { if( table.GetGoto(state_index, grammar.IndexOf(gram)) != -1 ) throw new ArgumentException("Grammar is not SLR(1)."); //TODO: custom exception with conflict info table.SetGoto(state_index, grammar.IndexOf(gram), next_state_index); } } // Reductions foreach( var item in canonical_sets.Sets[state_index] ) if( item.CursorPosition == item.Rule.RightHandSide.Count ) { // Is it [S'->S.] ? if( item.Rule.LeftHandSide == grammar.StartSymbol ) { if( table.GetAction(state_index, grammar.IndexOf(grammar.EndOfSourceSymbol)).Type != ParserTable.ActionType.Error ) throw new ArgumentException("Grammar is not SLR(1)."); //TODO: custom exception with conflict info table.SetAction( state_index, grammar.IndexOf(grammar.EndOfSourceSymbol), ParserTable.Action.Accept()); } // ... no, it's [A->alpha.] else { int rule_index = grammar.Rules.IndexOf(item.Rule); foreach( var follow_term in follow_sets[item.Rule.LeftHandSide] ) { if( table.GetAction(state_index, grammar.IndexOf(follow_term)).Type != ParserTable.ActionType.Error ) throw new ArgumentException("Grammar is not SLR(1)."); //TODO: custom exception with conflict info table.SetAction( state_index, grammar.IndexOf(follow_term), ParserTable.Action.Reduction(rule_index)); } } } } return table; }
public bool Equals( LR0CanonicalSets other ) { if( object.ReferenceEquals(other, null) ) return false; if( !other.Sets.SequenceEqual(other.Sets, new Utils.DelegateEqualityComparer<ISet<LR0Item>>( ( x, y ) => LR0CanonicalSets.AreEqual(x, y), ( obj ) => obj.GetHashCode())) ) return false; //TODO: Check transitions too? // If the sets are the same, the transition must be the same too. return true; }
static Grammar2() { var terminals = new TerminalSymbol[] { new TerminalSymbol("+"), new TerminalSymbol("*"), new TerminalSymbol("("), new TerminalSymbol(")"), new TerminalSymbol("i"), }; var grammaticals = new GrammaticalSymbol[] { new GrammaticalSymbol("S"), new GrammaticalSymbol("E"), new GrammaticalSymbol("E'"), new GrammaticalSymbol("T"), new GrammaticalSymbol("T'"), new GrammaticalSymbol("F"), }; var rules = new Rule[] { // S->E new Rule( grammaticals[0], new Symbol[] { grammaticals[1], }), // E->TE' new Rule( grammaticals[1], new Symbol[] { grammaticals[3], grammaticals[2], }), // E'->+TE' new Rule( grammaticals[2], new Symbol[] { terminals[0], grammaticals[3], grammaticals[2], }), // E'-> new Rule( grammaticals[2], new Symbol[] { }), // T->FT' new Rule( grammaticals[3], new Symbol[] { grammaticals[5], grammaticals[4], }), // T'->*FT' new Rule( grammaticals[4], new Symbol[] { terminals[1], grammaticals[5], grammaticals[4], }), // T'-> new Rule( grammaticals[4], new Symbol[] { }), // F->(E) new Rule( grammaticals[5], new Symbol[] { terminals[2], grammaticals[1], terminals[3], }), // F->i new Rule( grammaticals[5], new Symbol[] { terminals[4], }), }; BaseGrammar = new Grammar(terminals, grammaticals, rules, 0); RestrictedGrammar = new RestrictedStartSymbolGrammar(BaseGrammar); ExtendedGrammar = new ExtendedGrammar(RestrictedGrammar); EpsilonGrammaticals = new HashSet<GrammaticalSymbol>( new GrammaticalSymbol[] { grammaticals[2], grammaticals[4] }); FirstSets = new Dictionary<GrammaticalSymbol, ISet<TerminalSymbol>>(); // S: (,i FirstSets[BaseGrammar.Grammaticals[0]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { BaseGrammar.Terminals[2], BaseGrammar.Terminals[4], }); // E: (,i FirstSets[BaseGrammar.Grammaticals[1]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { BaseGrammar.Terminals[2], BaseGrammar.Terminals[4], }); // E': +,Eps FirstSets[BaseGrammar.Grammaticals[2]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { BaseGrammar.Terminals[0], EpsilonSymbol.Instance, }); // T: (,i FirstSets[BaseGrammar.Grammaticals[3]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { BaseGrammar.Terminals[2], BaseGrammar.Terminals[4], }); // T': *,Eps FirstSets[BaseGrammar.Grammaticals[4]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { BaseGrammar.Terminals[1], EpsilonSymbol.Instance, }); // F: (,i FirstSets[BaseGrammar.Grammaticals[5]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { BaseGrammar.Terminals[2], BaseGrammar.Terminals[4], }); FollowSets = new Dictionary<GrammaticalSymbol, ISet<TerminalSymbol>>(); // S: FollowSets[ExtendedGrammar.Grammaticals[0]] = new HashSet<TerminalSymbol>(); // E: ),EoS FollowSets[ExtendedGrammar.Grammaticals[1]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { ExtendedGrammar.Terminals[3], ExtendedGrammar.Terminals[5], }); // E': ),EoS FollowSets[ExtendedGrammar.Grammaticals[2]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { ExtendedGrammar.Terminals[3], ExtendedGrammar.Terminals[5], }); // T: +,),EoS FollowSets[ExtendedGrammar.Grammaticals[3]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { ExtendedGrammar.Terminals[0], ExtendedGrammar.Terminals[3], ExtendedGrammar.Terminals[5], }); // T': +,),EoS FollowSets[ExtendedGrammar.Grammaticals[4]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { ExtendedGrammar.Terminals[0], ExtendedGrammar.Terminals[3], ExtendedGrammar.Terminals[5], }); // F: +,*,),EoS FollowSets[ExtendedGrammar.Grammaticals[5]] = new HashSet<TerminalSymbol>(new TerminalSymbol[] { ExtendedGrammar.Terminals[0], ExtendedGrammar.Terminals[1], ExtendedGrammar.Terminals[3], ExtendedGrammar.Terminals[5], }); //TODO: Use real fixture!! LR0CanonicalSets = LR0CanonicalSets.Build(RestrictedGrammar); //TODO: Use real fixtures!! SLR1ParserTable = SLR1ParserTableBuilder.Build(ExtendedGrammar, LR0CanonicalSets, FollowSets); }