Beispiel #1
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)
        {
            var conflicts = new List <ParserGeneratorParserConflict>();
            var states    = CreateStates(grammar);

            // Create a parser state for each generator state.
            //
            var parserStates = states.ToDictionary(state => state, state => new ParserState(state.Id));

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

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

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

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

                            if (actions.ContainsKey(terminal))
                            {
                                var 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)
                    {
                        var terminal = (TerminalType)item.RuleItem.DotElement;

                        if (actions.ContainsKey(terminal))
                        {
                            var 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
                //
                var gotos = new Dictionary <NonterminalType, ParserState>();
                foreach (var transition in state.Transitions)
                {
                    if (transition.Key.ElementType != LanguageElementTypes.Nonterminal)
                    {
                        continue;
                    }

                    var nonterminal = (NonterminalType)transition.Key;
                    gotos.Add(nonterminal, parserStates[transition.Value]);
                }

                // Update the parser state.
                //
                var parserState = parserStates[state];
                foreach (var action in actions)
                {
                    parserState.Actions.Add(action.Key, action.Value);
                }

                foreach (var gotoItem in gotos)
                {
                    parserState.Gotos.Add(gotoItem.Key, gotoItem.Value);
                }
            }

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

            var result = new ParserGeneratorResult(parser, conflicts);

            return(result);
        }
Beispiel #2
0
        private List <GeneratorState> CreateStates(IGrammar grammar)
        {
            List <GeneratorState> states            = new List <GeneratorState>();
            List <GeneratorState> unevaluatedStates = new List <GeneratorState>();
            int stateId = 0;

            // Compute start state.
            //
            {
                HashSet <GeneratorStateItem> items = new HashSet <GeneratorStateItem>();
                foreach (RuleType rule in grammar.StartNonterminal.Rules)
                {
                    items.Add(new GeneratorStateItem(new GeneratorRuleItem(rule, 0)));
                }
                ComputeClosure(grammar, items);

                GeneratorState startState = new GeneratorState(stateId++, items);
                states.Add(startState);
                unevaluatedStates.Add(startState);
            }

            List <LanguageElementType> languageElements = new List <LanguageElementType>();

            languageElements.AddRange(grammar.GetTerminals());
            languageElements.AddRange(grammar.GetNonterminals());

            while (unevaluatedStates.Count > 0)
            {
                // Remove one of the evaluated states and process it.
                //
                GeneratorState state = unevaluatedStates[0];
                unevaluatedStates.RemoveAt(0);

                foreach (LanguageElementType languageElement in languageElements)
                {
                    HashSet <GeneratorStateItem> items = state.Apply(languageElement);
                    if (items != null)
                    {
                        ComputeClosure(grammar, items);

                        GeneratorState toState = null;
                        foreach (GeneratorState existingState in states)
                        {
                            if (existingState.Items.SetEquals(items))
                            {
                                toState = existingState;
                                break;
                            }
                        }
                        if (toState == null)
                        {
                            toState = new GeneratorState(stateId++, items);
                            states.Add(toState);
                            unevaluatedStates.Add(toState);
                        }

                        state.Transitions.Add(languageElement, toState);
                    }
                }
            }

            if (LinguaTrace.TraceSource.Switch.ShouldTrace(TraceEventType.Information))
            {
                foreach (GeneratorState state in states)
                {
                    LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_STATE, "{0}", state);
                }
            }

            return(states);
        }
Beispiel #3
0
        /// <summary>
        /// Performs syntax analysis against a sequence of terminals according to the <see cref="Grammar"/> used to create the <see cref="Parser"/>.
        /// </summary>
        /// <param name="terminalReader">Retrieves a sequence of <see cref="Terminal"/> objects.</param>
        /// <returns>If syntax analysis succeeds, returns the <see cref="Nonterminal"/> associated with <see cref="Grammar.StartNonterminal"/>.  Otherwise, <value>null</value> is returned.</returns>
        public Nonterminal Parse(ITerminalReader terminalReader)
        {
            var stack = new ParserStack();

            stack.Push(null, InitialState);

            var terminal = terminalReader.ReadTerminal();

            while (terminal != null)
            {
                if (terminal.ElementType.Ignore)
                {
                    terminal = terminalReader.ReadTerminal();
                }
                else
                {
                    var action = stack.Peek().State.GetAction(terminal.ElementType);

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

                    if (action == null)
                    {
                        return(null);
                    }

                    switch (action.ActionType)
                    {
                    case ParserActionTypes.Accept:
                    {
                        var reduce = (ParserActionAccept)action;
                        var rule   = reduce.Rule;
                        var lhs    = Reduce(stack, rule);
                        return(lhs);
                    }

                    case ParserActionTypes.Shift:
                    {
                        var shift = (ParserActionShift)action;
                        stack.Push(terminal, shift.State);
                        terminal = terminalReader.ReadTerminal();
                    }
                    break;

                    case ParserActionTypes.Reduce:
                    {
                        var reduce = (ParserActionReduce)action;
                        var rule   = reduce.Rule;
                        var lhs    = Reduce(stack, rule);

                        // Push the LHS nonterminal on the stack.
                        //
                        stack.Push(lhs, stack.Peek().State.GetGoto(lhs.ElementType));
                    }
                    break;

                    default:
                        throw new InvalidOperationException(string.Format("Unrecognized action type {0}.", action.ActionType));
                    }
                }
            }
            return(null);
        }