Пример #1
0
 public void BuildWithValidGrammar( RestrictedStartSymbolGrammar grammar, LR0CanonicalSets expected )
 {
     var actual = LR0CanonicalSets.Build(grammar);
     Assert.NotNull(actual);
     Assert.True(actual.Equals(expected));
 }
Пример #2
0
        /// <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;
        }
Пример #3
0
        /// <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;
        }
Пример #4
0
        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;
        }
Пример #5
0
        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);
        }