예제 #1
0
        /// <summary>
        /// Gets possible inputs that allows for reaching the specified state from state 0
        /// </summary>
        /// <param name="state">A LR state</param>
        /// <returns>A list of possible inputs for reaching the specified state</returns>
        public List <Phrase> GetInputsFor(State state)
        {
            List <Phrase> result = new List <Phrase>();

            // for all paths from state 0 to the specified state
            foreach (ENode start in GetPathsTo(state))
            {
                Phrase input = new Phrase();
                ENode  node  = start;
                while (node.next != null)
                {
                    Terminal terminal = node.transition as Terminal;
                    if (terminal != null)
                    {
                        // this is terminal => simply add it to the input
                        input.Append(terminal);
                    }
                    else
                    {
                        // this is a variable => try to decompose it
                        BuildInput(input, node.transition as Variable, new Stack <RuleChoice>());
                    }
                    node = node.next;
                }
                result.Add(input);
            }
            return(result);
        }
예제 #2
0
        /// <summary>
        /// Builds the input by decomposing the given variable
        /// </summary>
        /// <param name="sample">The input sample to build</param>
        /// <param name="var">The variable to decompose</param>
        /// <param name="stack">The stack of rule definitions currently in use for the decomposition</param>
        /// <remarks>
        /// This methods recursively triggers the production of encoutered variables to arrive to the terminal symbols.
        /// The methods also tries do not go into an infinite loop by keeping track of the rule definitions that are currently used.
        /// If a rule definition has already been used (is in the stack) the method avoids it
        /// </remarks>
        private void BuildInput(Phrase sample, Variable var, Stack <RuleChoice> stack)
        {
            // TODO: there is a bug in this method, it may call itself forever

            // if the variable to decompose is nullable (epsilon is in the FIRSTS state), stop here
            if (var.Firsts.Contains(Epsilon.Instance))
            {
                return;
            }

            // builds the list of possible rule definition for the variable
            List <RuleChoice> definitions = new List <RuleChoice>();

            foreach (Rule rule in var.Rules)
            {
                definitions.Add(rule.Body.Choices[0]);
            }

            // try to find a rule definition that is not already used (in the stack)
            RuleChoice def = null;

            foreach (RuleChoice d in definitions)
            {
                if (!stack.Contains(d))
                {
                    // if it is not in the stack of rule definition
                    // select it and stop
                    def = d;
                    break;
                }
            }

            // if all identified rule definitions are in the stack (currently in use)
            // f**k it, just use the first one ...
            if (def == null)
            {
                def = definitions[0];
            }

            RuleChoice[] stackElements = stack.ToArray();
            // push the rule definition to use onto the stack
            stack.Push(def);
            // walk the rule definition to build the sample
            for (int i = 0; i != def.Length; i++)
            {
                RuleBodyElement part = def[i];
                if (part.Symbol is Terminal)
                {
                    // easy, just add it to the sample
                    sample.Append(part.Symbol as Terminal);
                }
                else
                {
                    bool symbolFound = false;
                    // TODO: cleanup this code, this is really not a nice patch!!
                    // TODO: this is surely ineficient, but I don't understand the algorithm to do better yet
                    // The idea is to try and avoid infinite recursive call by checking the symbol was not already processed before
                    // This code checks whether the variable in this part is not already in one of the rule definition currently in the stack
                    foreach (RuleChoice definition in stackElements)
                    {
                        // for all elements
                        for (int j = 0; j != definition.Length; j++)
                        {
                            RuleBodyElement definitionPart = definition[j];
                            if (definitionPart.Symbol.Equals(part.Symbol))
                            {
                                symbolFound = true;
                            }
                        }
                    }
                    // if part.Symbol is not the same as another part.symbol found in a previous definition
                    if (!symbolFound)
                    {
                        BuildInput(sample, part.Symbol as Variable, stack);
                    }
                    // TODO: what do we do if the variable was found?
                }
            }
            stack.Pop();
        }
예제 #3
0
파일: Builder.cs 프로젝트: sebgod/hime
        /// <summary>
        /// Build the specified grammar
        /// </summary>
        /// <param name="method">The parsing method to use</param>
        /// <returns>The resulting LR graph, or <c>null</c> if it could not be generated</returns>
        public Graph Build(ParsingMethod method)
        {
            // build the graph
            switch (method)
            {
            case ParsingMethod.LR0:
                graph = GetGraphLR0();
                break;

            case ParsingMethod.LR1:
                graph = GetGraphLR1();
                break;

            case ParsingMethod.LALR1:
                graph = GetGaphLALR1();
                break;

            case ParsingMethod.RNGLR1:
                graph = GetGraphRNGLR1();
                break;

            case ParsingMethod.RNGLALR1:
                graph = GetGraphRNGLALR1();
                break;
            }

            // builds the set of conflicts
            inverse = new GraphInverse(graph);
            foreach (State state in graph.States)
            {
                if (state.Conflicts.Count != 0)
                {
                    List <Phrase> samples = inverse.GetInputsFor(state);
                    foreach (Conflict conflict in state.Conflicts)
                    {
                        foreach (Phrase sample in samples)
                        {
                            Phrase temp = new Phrase(sample);
                            temp.Append(conflict.ConflictSymbol);
                            conflict.AddExample(temp);
                        }
                        conflicts.Add(conflict);
                    }
                }
                List <List <State> > paths = null;
                foreach (Symbol symbol in state.Transitions)
                {
                    Terminal terminal = symbol as Terminal;
                    if (terminal == null)
                    {
                        continue;
                    }
                    if (terminal.Context == 0)
                    {
                        continue;
                    }
                    // this is a contextual terminal, can we reach this state without the right context being available
                    if (paths == null)
                    {
                        paths = inverse.GetStatePathsTo(state);
                    }
                    foreach (List <State> path in paths)
                    {
                        path.Add(state);                         // append this state
                        bool found = false;
                        for (int i = 0; i != path.Count - 1; i++)
                        {
                            State element = path[i];
                            foreach (Item item in element.Items)
                            {
                                if (item.DotPosition == 0 && item.BaseRule.Context == terminal.Context)
                                {
                                    // this is the opening of a context only if we are not going to the next state using the associated variable
                                    found |= !state.HasTransition(item.BaseRule.Head) || state.GetChildBy(item.BaseRule.Head) != path[i + 1];
                                    break;
                                }
                            }
                            if (found)
                            {
                                break;
                            }
                        }
                        foreach (Item item in state.Items)
                        {
                            if (item.DotPosition == 0 && item.BaseRule.Context == terminal.Context)
                            {
                                found = true;
                                break;
                            }
                        }
                        if (!found)
                        {
                            // this is problematic path
                            ContextualError error = new ContextualError(state);
                            foreach (Item item in state.Items)
                            {
                                if (item.Action == LRActionCode.Shift && item.GetNextSymbol() == terminal)
                                {
                                    error.AddItem(item);
                                }
                            }
                            errors.Add(error);
                        }
                    }
                }
            }
            return(graph);
        }