Example #1
0
        /// <summary>
        /// Gets all nonterminals defined by the <see cref="Grammar" />.
        /// </summary>
        /// <returns>An array of <see cref="NonterminalType" /> that represents all nonterminals defined by the <see cref="Grammar" />.</returns>
        public NonterminalType[] GetNonterminals()
        {
            var nonterminals = new NonterminalType[_nonterminals.Values.Count];

            _nonterminals.Values.CopyTo(nonterminals, 0);
            return(nonterminals);
        }
Example #2
0
        /// <summary>
        /// Gets the <see cref="ParserState"/> associated with a <see cref="NonterminalType"/> as defined by <see cref="Gotos"/>.
        /// </summary>
        /// <param name="nonterminalType">A <see cref="NonterminalType"/> object.</param>
        /// <returns>The <see cref="ParserState"/> associated with <paramref name="nonterminalType"/> as defined by <see cref="Gotos"/>.
        /// Returns <value>null</value> if no such <see cref="ParserState"/> exists.</returns>
        public ParserState GetGoto(NonterminalType nonterminalType)
        {
            ParserState state;

            if (m_gotos.TryGetValue(nonterminalType, out state))
            {
                return(state);
            }
            return(null);
        }
Example #3
0
        /// <summary>
        /// Retrieves the terminal or nonterminal definition from the specified <see cref="Type"/> and adds it to the
        /// <see cref="Grammar"/>.
        /// </summary>
        /// <param name="type">A <see cref="Type"/> containing a terminal or nonterminal definition.</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>
        /// <returns>The <see cref="LanguageElementType"/> added to the <see cref="Grammar"/>.  If the specified <see cref="Type"/>
        /// did not represent a terminal or nonterminal definition, <value>null</value> is returned.
        /// </returns>
        public LanguageElementType Load(Type type, string name)
        {
            if (TypeIsTerminal(type, name))
            {
                TerminalType terminalType = new TerminalType(type);
                m_terminals.Add(type, terminalType);
                return(terminalType);
            }

            if (TypeIsNonterminal(type, name))
            {
                NonterminalType nonterminalType = new NonterminalType(type);
                m_nonterminals.Add(type, nonterminalType);
                return(nonterminalType);
            }

            return(null);
        }
Example #4
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);
                }
            }
        }
Example #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RuleType"/> class.
        /// </summary>
        /// <param name="methodInfo">The <see cref="MethodInfo"/> associated with this <see cref="RuleType"/>.</param>
        /// <param name="priority">The priority of this rule used to resolve conflicts with other rules during parser generation.</param>
        /// <param name="lhs">The <see cref="NonterminalType"/> representing the LHS of this rule.</param>
        /// <param name="rhs">The collection of <see cref="LanguageElementType"/> representing the RHS of this rule.</param>
        public RuleType(MethodInfo methodInfo, int priority, NonterminalType lhs, LanguageElementType[] rhs)
        {
            var sb = new StringBuilder();

            sb.Append(methodInfo.Name);
            sb.Append("[");
            string prefix = null;

            foreach (var parameter in methodInfo.GetParameters())
            {
                sb.Append(prefix); prefix = ",";
                sb.Append(parameter.ParameterType.Name);
            }
            sb.Append("]");
            var name = sb.ToString();

            FullName  = string.Format("{0}::{1}", methodInfo.DeclaringType.FullName, name);
            Name      = name;
            _delegate = parameters => methodInfo.Invoke(null, parameters);

            Priority = priority;
            _lhs     = lhs;
            Rhs      = rhs;
        }
Example #6
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RuleType"/> class.
        /// </summary>
        /// <param name="methodInfo">The <see cref="MethodInfo"/> associated with this <see cref="RuleType"/>.</param>
        /// <param name="priority">The priority of this rule used to resolve conflicts with other rules during parser generation.</param>
        /// <param name="lhs">The <see cref="NonterminalType"/> representing the LHS of this rule.</param>
        /// <param name="rhs">The collection of <see cref="LanguageElementType"/> representing the RHS of this rule.</param>
        public RuleType(MethodInfo methodInfo, int priority, NonterminalType lhs, LanguageElementType[] rhs)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(methodInfo.Name);
            sb.Append("[");
            string prefix = null;

            foreach (ParameterInfo parameter in methodInfo.GetParameters())
            {
                sb.Append(prefix); prefix = ",";
                sb.Append(parameter.ParameterType.Name);
            }
            sb.Append("]");
            string name = sb.ToString();

            m_fullName = string.Format("{0}::{1}", methodInfo.DeclaringType.FullName, name);
            m_name     = name;
            m_delegate = delegate(LanguageElement[] parameters) { methodInfo.Invoke(null, parameters); };

            m_priority = priority;
            m_lhs      = lhs;
            m_rhs      = rhs;
        }
Example #7
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);
                }
            }
        }
Example #8
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;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Example #9
0
        /// <summary>
        /// Constructs a new <see cref="Parser"/> which can recoganize the specified <see cref="IGrammar"/>.
        /// </summary>
        /// <param name="grammar">The <see cref="IGrammar"/> to be recognized by the <see cref="Parser"/>.</param>
        /// <returns>A <see cref="ParserGeneratorResult"/> containing <see cref="Parser"/> and information pertaining to the
        /// success or failure of the generation process.
        /// </returns>
        public ParserGeneratorResult GenerateParser(IGrammar grammar)
        {
            List <ParserGeneratorParserConflict> conflicts = new List <ParserGeneratorParserConflict>();

            List <GeneratorState> states = CreateStates(grammar);

            // Create a parser state for each generator state.
            //
            Dictionary <GeneratorState, ParserState> parserStates = new Dictionary <GeneratorState, ParserState>();

            foreach (GeneratorState state in states)
            {
                parserStates.Add(state, new ParserState(state.Id));
            }

            foreach (GeneratorState state in states)
            {
                LinguaTrace.TraceEvent(TraceEventType.Verbose, LinguaTraceId.ID_GENERATE_PROCESS_STATE, "{0}", state);

                List <GeneratorStateItem> items = new List <GeneratorStateItem>(state.Items);
                items.Sort();

                // Construct the list of actions associated with the parser state.
                //
                Dictionary <TerminalType, ParserAction>      actions     = new Dictionary <TerminalType, ParserAction>();
                Dictionary <ParserAction, GeneratorRuleItem> actionRules = new Dictionary <ParserAction, GeneratorRuleItem>();
                foreach (GeneratorStateItem item in items)
                {
                    LinguaTrace.TraceEvent(TraceEventType.Verbose, LinguaTraceId.ID_GENERATE_PROCESS_ITEM, "{0}", item);

                    if (item.RuleItem.DotElement == null)
                    {
                        foreach (TerminalType terminal in item.RuleItem.Rule.Lhs.Follow)
                        {
                            LinguaTrace.TraceEvent(TraceEventType.Verbose, LinguaTraceId.ID_GENERATE_PROCESS_TERMINAL, "{0}", terminal);

                            if (actions.ContainsKey(terminal))
                            {
                                ParserGeneratorParserConflict conflict = new ParserGeneratorParserConflict(
                                    actionRules[actions[terminal]].ToString(),
                                    item.RuleItem.ToString());

                                LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_PROCESS_CONFLICT, "{0}", conflict);

                                conflicts.Add(conflict);
                            }
                            else if (item.RuleItem.Rule.Lhs.IsStart &&
                                     terminal.IsStop)
                            {
                                ParserAction action = new ParserActionAccept(item.RuleItem.Rule);

                                LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_PROCESS_ACTION, "{0}", action);

                                actions.Add(terminal, action);
                                actionRules.Add(action, item.RuleItem);
                            }
                            else
                            {
                                ParserAction action = new ParserActionReduce(item.RuleItem.Rule);

                                LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_PROCESS_ACTION, "{0}", action);

                                actions.Add(terminal, action);
                                actionRules.Add(action, item.RuleItem);
                            }
                        }
                    }
                    else if (item.RuleItem.DotElement.ElementType == LanguageElementTypes.Terminal)
                    {
                        TerminalType terminal = (TerminalType)item.RuleItem.DotElement;

                        if (actions.ContainsKey(terminal))
                        {
                            ParserGeneratorParserConflict conflict = new ParserGeneratorParserConflict(
                                actionRules[actions[terminal]].ToString(),
                                item.RuleItem.ToString());

                            LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_PROCESS_CONFLICT, "{0}", conflict);

                            conflicts.Add(conflict);
                        }
                        else
                        {
                            ParserAction action = new ParserActionShift(parserStates[state.Transitions[terminal]]);

                            LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_PROCESS_ACTION, "{0}", action);

                            actions.Add(terminal, action);
                            actionRules.Add(action, item.RuleItem);
                        }
                    }
                }

                // Construct the GOTO table
                //
                Dictionary <NonterminalType, ParserState> gotos = new Dictionary <NonterminalType, ParserState>();
                foreach (KeyValuePair <LanguageElementType, GeneratorState> transition in state.Transitions)
                {
                    if (transition.Key.ElementType == LanguageElementTypes.Nonterminal)
                    {
                        NonterminalType nonterminal = (NonterminalType)transition.Key;
                        gotos.Add(nonterminal, parserStates[transition.Value]);
                    }
                }

                // Update the parser state.
                //
                ParserState parserState = parserStates[state];
                foreach (KeyValuePair <TerminalType, ParserAction> action in actions)
                {
                    parserState.Actions.Add(action.Key, action.Value);
                }

                foreach (KeyValuePair <NonterminalType, ParserState> gotoItem in gotos)
                {
                    parserState.Gotos.Add(gotoItem.Key, gotoItem.Value);
                }
            }

            Parser parser = new Parser(parserStates[states[0]]);

            ParserGeneratorResult result = new ParserGeneratorResult(parser, conflicts);

            return(result);
        }
Example #10
0
 /// <summary>
 /// Gets the <see cref="ParserState"/> associated with a <see cref="NonterminalType"/> as defined by <see cref="Gotos"/>.
 /// </summary>
 /// <param name="nonterminalType">A <see cref="NonterminalType"/> object.</param>
 /// <returns>The <see cref="ParserState"/> associated with <paramref name="nonterminalType"/> as defined by <see cref="Gotos"/>.
 /// Returns <value>null</value> if no such <see cref="ParserState"/> exists.</returns>
 public ParserState GetGoto(NonterminalType nonterminalType)
 {
     ParserState state;
     return _gotos.TryGetValue(nonterminalType, out state) ? state : null;
 }
Example #11
0
 /// <summary>
 /// Gets all nonterminals defined by the <see cref="Grammar" />.
 /// </summary>
 /// <returns>An array of <see cref="NonterminalType" /> that represents all nonterminals defined by the <see cref="Grammar" />.</returns>
 public NonterminalType[] GetNonterminals()
 {
     NonterminalType[] nonterminals = new NonterminalType[m_nonterminals.Values.Count];
     m_nonterminals.Values.CopyTo(nonterminals, 0);
     return nonterminals;
 }
Example #12
0
        /// <summary>
        /// Retrieves the terminal or nonterminal definition from the specified <see cref="Type"/> and adds it to the
        /// <see cref="Grammar"/>.
        /// </summary>
        /// <param name="type">A <see cref="Type"/> containing a terminal or nonterminal definition.</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>
        /// <returns>The <see cref="LanguageElementType"/> added to the <see cref="Grammar"/>.  If the specified <see cref="Type"/>
        /// did not represent a terminal or nonterminal definition, <value>null</value> is returned.
        /// </returns>
        public LanguageElementType Load(Type type, string name)
        {
            if (TypeIsTerminal(type, name))
            {
                TerminalType terminalType = new TerminalType(type);
                m_terminals.Add(type, terminalType);
                return terminalType;
            }

            if (TypeIsNonterminal(type, name))
            {
                NonterminalType nonterminalType = new NonterminalType(type);
                m_nonterminals.Add(type, nonterminalType);
                return nonterminalType;
            }

            return null;
        }
Example #13
0
 /// <summary>
 /// Gets the <see cref="ParserState"/> associated with a <see cref="NonterminalType"/> as defined by <see cref="Gotos"/>.
 /// </summary>
 /// <param name="nonterminalType">A <see cref="NonterminalType"/> object.</param>
 /// <returns>The <see cref="ParserState"/> associated with <paramref name="nonterminalType"/> as defined by <see cref="Gotos"/>.
 /// Returns <value>null</value> if no such <see cref="ParserState"/> exists.</returns>
 public ParserState GetGoto(NonterminalType nonterminalType)
 {
     ParserState state;
     if (m_gotos.TryGetValue(nonterminalType, out state))
     {
         return state;
     }
     return null;
 }
Example #14
0
 /// <summary>
 /// Gets the <see cref="ParserState"/> associated with a <see cref="NonterminalType"/> as defined by <see cref="Gotos"/>.
 /// </summary>
 /// <param name="nonterminalType">A <see cref="NonterminalType"/> object.</param>
 /// <returns>The <see cref="ParserState"/> associated with <paramref name="nonterminalType"/> as defined by <see cref="Gotos"/>.
 /// Returns <value>null</value> if no such <see cref="ParserState"/> exists.</returns>
 public ParserState GetGoto(NonterminalType nonterminalType)
 {
     ParserState state;
     return _gotos.TryGetValue(nonterminalType, out state) ? state : null;
 }