public static StateTransitionGraph Build(Grammar.Grammar grammar)
        {
            var root = StateTransitionGraphBuilder.BuildGraph(grammar);

            return(new StateTransitionGraph(root));
        }
        public static RootNode BuildGraph(Grammar.Grammar grammar)
        {
            {
                var nonTerminalHeads = ProcessNonTerminalsHeads();
                ProcessRemainingNonTerminalsItems(nonTerminalHeads);

                var rootHead = nonTerminalHeads[grammar.Root.NonTerminalUsage.Impl];
                return(new RootNode().WithChild(rootHead));
            }

            IReadOnlyDictionary <GrammarNonTerminal, Node> ProcessNonTerminalsHeads()
            {
                var nonTerminalHeads = new Dictionary <GrammarNonTerminal, Node>();

                foreach (var nonTerminal in grammar.NonTerminals)
                {
                    ProcessSingle(nonTerminal);
                }

                return(nonTerminalHeads);

                Node ProcessSingle(GrammarNonTerminal nonTerminal)
                {
                    if (nonTerminalHeads.TryGetValue(nonTerminal, out var aleadyProcessed))
                    {
                        if (aleadyProcessed == null)
                        {
                            var msg = $"Recursive non-terminal {nonTerminal.Name} usage cannot be placed " +
                                      "on the very start of non-terminal body. It would cause " +
                                      "infinite recursion.";
                            throw new StateTransitionException(msg,
                                                               StateTransitionException.Id.InfiniteRecursion);
                        }

                        return(aleadyProcessed);
                    }

                    // marks that processing of `nonTerminal` started
                    nonTerminalHeads.Add(nonTerminal, null);

                    var heads = new NodesCollection();

                    foreach (var orConditionOperand in nonTerminal.Body.OrConditionOperands)
                    {
                        var bodyItem = orConditionOperand[0];

                        switch (bodyItem)
                        {
                        case GrammarTerminalUsage terminalUsage:
                            var terminalNode = new TerminalNode(terminalUsage);
                            heads.Add(terminalNode);
                            break;

                        case GrammarNonTerminalUsage nonTerminalUsage:
                            var newNonTerminalHead   = ProcessSingle(nonTerminalUsage.Impl);
                            var nonTerminalUsageNode =
                                new NonTerminalUsageNode(nonTerminalUsage.Name, newNonTerminalHead);
                            heads.Add(nonTerminalUsageNode);
                            break;

                        default:
                            throw new StateTransitionException(
                                      $"Unknown non-terminal body item type: {bodyItem.Type}",
                                      StateTransitionException.Id.UnknownNonTerminalBodyItemType);
                        }
                    }

                    var head = heads.Count > 1 ? new BranchNode(heads) : heads[0];

                    if (nonTerminalHeads[nonTerminal] != null)
                    {
                        throw new StateTransitionException("Unexpected error.",
                                                           StateTransitionException.Id.UnexpectedError);
                    }

                    nonTerminalHeads[nonTerminal] = head;
                    return(head);
                }
            }

            void ProcessRemainingNonTerminalsItems(IReadOnlyDictionary <GrammarNonTerminal, Node> nonTerminalHeads)
            {
                foreach (var nonTerminal in grammar.NonTerminals)
                {
                    ProcessSingle(nonTerminal);
                }

                void ProcessSingle(GrammarNonTerminal nonTerminal)
                {
                    var head = nonTerminalHeads[nonTerminal];

                    for (var operandIndex = 0;
                         operandIndex < nonTerminal.Body.OrConditionOperands.Count;
                         operandIndex++)
                    {
                        var currentTail = head is BranchNode node
                            ? node.Heads.ToList()[operandIndex]
                            : head;

                        foreach (var bodyItem in nonTerminal.Body.OrConditionOperands[operandIndex].Skip(1))
                        {
                            switch (bodyItem)
                            {
                            case GrammarTerminalUsage terminalUsage:
                                var terminalNode = new TerminalNode(terminalUsage);
                                currentTail.AddChild(terminalNode);
                                currentTail = terminalNode;
                                break;

                            case GrammarNonTerminalUsage nonTerminalUsage:
                                var newNonTerminalHead   = nonTerminalHeads[nonTerminalUsage.Impl];
                                var nonTerminalUsageNode =
                                    new NonTerminalUsageNode(nonTerminalUsage.Name, newNonTerminalHead);
                                currentTail.AddChild(nonTerminalUsageNode);
                                currentTail = nonTerminalUsageNode;
                                break;

                            default:
                                throw new StateTransitionException(
                                          $"Unknown non-terminal body item type: {bodyItem.Type}",
                                          StateTransitionException.Id.UnknownNonTerminalBodyItemType);
                            }
                        }
                    }
                }
            }
        }
Example #3
0
 /// <summary>
 /// Crea la colección canónica a partir de la gramática suministrada
 /// </summary>
 public CanonicalCollection(Grammar.Grammar grammar)
 {
     this.States  = new List <State>();
     this.grammar = grammar;
     getCanonicalCollection();
 }