Пример #1
0
        /// <summary>
        /// Computes a new set of <see cref="GeneratorStateItem"/> objects based on items in the current <see cref="GeneratorState"/>
        /// identified by the specified <see cref="LanguageElementType"/>
        /// </summary>
        /// <param name="languageElementType">A <see cref="LanguageElementType"/> object.</param>
        /// <returns>A <see cref="HashSet{GeneratorStateItem}"/> containing items identified by <paramref name="languageElementType"/>.</returns>
        /// <remarks>
        /// If this <see cref="GeneratorState"/> contains a <see cref="GeneratorRuleItem"/> representing an LR(0) item of the
        /// form <value>X→Y₁…○Z…Yₓ</value> and <see cref="LanguageElementType"/> is <value>Z</value>, the
        /// result will contain a <see cref="GeneratorRuleItem"/> representing an LR(0) item of the
        /// form <value>X→Y₁…Z○…Yₓ</value>.
        /// </remarks>
        public HashSet <GeneratorStateItem> Apply(LanguageElementType languageElementType)
        {
            HashSet <GeneratorStateItem> result = null;

            foreach (GeneratorStateItem item in Items)
            {
                if (item.RuleItem.DotElement == languageElementType)
                {
                    if (result == null)
                    {
                        result = new HashSet <GeneratorStateItem>();
                    }
                    result.Add(new GeneratorStateItem(new GeneratorRuleItem(item.RuleItem.Rule, item.RuleItem.Dot + 1)));
                }
            }

            return(result);
        }
Пример #2
0
        private void ComputeClosure(IGrammar grammar, HashSet <GeneratorStateItem> items)
        {
            // Continue to loop until new more elements are added to the state.
            //
            bool stateModified = true;

            while (stateModified)
            {
                HashSet <GeneratorStateItem> newItems = new HashSet <GeneratorStateItem>();

                // Iterate over the current elements in the state and determine (possible) new
                // elements to be added.
                //
                foreach (GeneratorStateItem item in items)
                {
                    LanguageElementType languageElement = item.RuleItem.DotElement;
                    if (languageElement != null &&
                        languageElement.ElementType == LanguageElementTypes.Nonterminal)
                    {
                        NonterminalType nonterminal = (NonterminalType)languageElement;

                        foreach (RuleType rule in nonterminal.Rules)
                        {
                            GeneratorStateItem newItem = new GeneratorStateItem(new GeneratorRuleItem(rule, 0));
                            newItems.Add(newItem);
                        }
                    }
                }

                // Exit loop if all potential new elements already exist in state.  Otherwise, add new elements
                // and repeat process.
                //
                if (newItems.IsSubsetOf(items))
                {
                    stateModified = false;
                }
                else
                {
                    items.UnionWith(newItems);
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Retrieves all rule definitions from the specified <see cref="Type"/> and adds them to the <see cref="Grammar"/>.
        /// </summary>
        /// <param name="type">A <see cref="Type"/> containing rule definitions.</param>
        /// <param name="name">The name of the grammar being loaded as defined by <see cref="GrammarAttribute"/>.  Specify <value>null</value> to load <paramref name="type"/> regardless of grammar name.</param>
        public void LoadRules(Type type, string name)
        {
            // Ensure type is in specified grammar.
            //
            if (!IsGrammarType(type, name))
            {
                return;
            }

            // Load rules defined by type.
            //
            foreach (MethodInfo method in type.GetMethods())
            {
                ParameterInfo[] parameters = method.GetParameters();

                if (MethodIsRule(method, parameters))
                {
                    // Determine priority associated with rule.
                    //
                    int      priority   = 0;
                    object[] attributes = method.GetCustomAttributes(typeof(RuleAttribute), false);
                    if (attributes.Length > 0)
                    {
                        RuleAttribute attribute = attributes[0] as RuleAttribute;
                        if (attribute != null)
                        {
                            priority = attribute.Priority;
                        }
                    }

                    // Find the grammer language elements associated with each parameter member.
                    //
                    NonterminalType            lhs = null;
                    List <LanguageElementType> rhs = new List <LanguageElementType>();
                    for (int idx = 0; idx < parameters.Length; ++idx)
                    {
                        Type parameterType = parameters[idx].ParameterType;

                        if (idx == 0)
                        {
                            NonterminalType nonterminal;
                            if (m_nonterminals.TryGetValue(parameterType, out nonterminal))
                            {
                                lhs = nonterminal;
                            }
                            else
                            {
                                throw new InvalidOperationException();
                            }
                        }
                        else
                        {
                            NonterminalType nonterminal;
                            if (m_nonterminals.TryGetValue(parameterType, out nonterminal))
                            {
                                rhs.Add(nonterminal);
                            }
                            else
                            {
                                TerminalType terminal;
                                if (m_terminals.TryGetValue(parameterType, out terminal))
                                {
                                    rhs.Add(terminal);
                                }
                                else
                                {
                                    // If parameterType is currently not defined by the grammar, attempt to process it
                                    // now.  This occurs when OptionalTerminal<> and OptionalNonterminal<> types
                                    // appear in the RHS side of a rule.
                                    //
                                    LanguageElementType languageElementType = Load(parameterType, name);
                                    if (languageElementType != null)
                                    {
                                        rhs.Add(languageElementType);
                                        LoadRules(parameterType, name);
                                    }
                                    else
                                    {
                                        throw new InvalidOperationException("Unrecognized rule argument.");
                                    }
                                }
                            }
                        }
                    }

                    // Create the rule.
                    //
                    RuleType rule = new RuleType(method, priority, lhs, rhs.ToArray());
                    lhs.Rules.Add(rule);
                }
            }
        }
Пример #4
0
        private void ComputeFollow()
        {
            StartNonterminal.Follow.Add(StopTerminal);

            // Continue adding elements until no more changes to FOLLOW are made.
            //
            bool change = true;

            while (change)
            {
                change = false;

                // Iterate over all nonterminals and their rules.
                //
                foreach (NonterminalType x in m_nonterminals.Values)
                {
                    foreach (RuleType rule in x.Rules)
                    {
                        // For rules of the form X -> ... Y B1 B2 ... Bn, add FIRST(Bi) (excluding e)
                        // to FOLLOW(Y) if FIRST(Bj) contains e for all j < i.  Add FOLLOW(X) to
                        // FOLLOW(Y) if FIRST(Bi) contains e for all i.
                        //
                        for (int idx = 0; idx < rule.Rhs.Length; ++idx)
                        {
                            if (rule.Rhs[idx].ElementType == LanguageElementTypes.Nonterminal)
                            {
                                NonterminalType y = (NonterminalType)rule.Rhs[idx];

                                bool epsilonInAllB = true;
                                for (int j = idx + 1; j < rule.Rhs.Length; ++j)
                                {
                                    LanguageElementType b = rule.Rhs[j];

                                    HashSet <TerminalType> bFirst = b.First.GetSetExcludingEpsilon();
                                    if (bFirst.Count > 0 &&
                                        !bFirst.IsSubsetOf(y.Follow))
                                    {
                                        y.Follow.UnionWith(bFirst);
                                        change = true;
                                    }

                                    if (!b.First.ContainsEpsilon)
                                    {
                                        epsilonInAllB = false;
                                        break;
                                    }
                                }

                                if (epsilonInAllB)
                                {
                                    if (x.Follow.Count > 0 &&
                                        !x.Follow.IsSubsetOf(y.Follow))
                                    {
                                        y.Follow.UnionWith(x.Follow);
                                        change = true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }