/// <summary>
        /// Construct a new NameParser.
        /// </summary>
        /// <param name="namelistSource">The source for namelists to use.</param>
        /// <param name="seed">The random seed to use for NameFragment selection.</param>
        /// <param name="lexer">The <see cref="IPatternLexer"/> to use to process patterns.</param>
        public NameParser(INamelistSource namelistSource, IPatternLexer lexer, int seed)
        {
            _namelistSource = namelistSource;

            _lexer = lexer;

            _random = new Random(seed);

            _initialized = false;
        }
Example #2
0
        /// <summary>
        /// Создаёт последовательность узлов в дереве c помощью указанного лексера шаблонов команд.
        /// </summary>
        /// <param name="lexer">Лексер.</param>
        /// <param name="startNode">Стартовый узел дерева.</param>
        /// <returns>Последний узел созданной последовательности типа <see cref="TokenType.EndOfText"/>.</returns>
        internal static CommandTreeNode CreateTreeNodes(IPatternLexer lexer, CommandTreeNode startNode)
        {
            Debug.Assert(lexer != null);
            Debug.Assert(startNode != null);

            var curPointer           = startNode;
            var unprocessedOpenParen = 0;
            var stackAfterOpenParen  = new Stack <CommandTreeNode>();

            while (curPointer.TokenPrototype.Type != TokenType.EndOfText)
            {
                var token = lexer.NextPatternToken();
                if (token.Type == TokenType.OpenParen)
                {
                    unprocessedOpenParen++;
                }
                else if (token.Type == TokenType.CloseParen)
                {
                    if (stackAfterOpenParen.Count == 0)
                    {
                        throw new WrongPatternException(token,
                                                        "Количество закрывающих скобок превышает количество открывающих.");
                    }

                    if (unprocessedOpenParen > 0)
                    {
                        throw new WrongPatternException(token,
                                                        "Группа не может быть пустой (внутри скобок должны быть значимые токены).");
                    }

                    var startAfterNode = stackAfterOpenParen.Pop();
                    var endNode        = curPointer;
                    endNode.IsGroupEnd = true;

                    var actionPeek = lexer.NextPatternToken();

                    if (actionPeek.Type == TokenType.Plus)
                    {
                        // создаём цикличную ссылку, тем самым, группа может повторяться.

                        if (endNode.NextNodes.ContainsKey(startAfterNode.TokenPrototype))
                        {
                            throw new WrongPatternException(actionPeek, "Группа не может содержать только одну подгруппу.");
                        }

                        var backReference = new CommandTreeNode.Reference(startAfterNode, true);
                        endNode.NextNodes.Add(startAfterNode.TokenPrototype, backReference);
                    }
                    else
                    {
                        throw new WrongPatternException(actionPeek,
                                                        $"После закрывающей скобки может быть только квантификатор '+' - 1 или более раз. Но был встречен токен: {actionPeek}.");
                    }
                }
                else
                {
                    if (curPointer.NextNodes.TryGetValue(token, out CommandTreeNode.Reference reference))
                    {
                        curPointer = reference.Node;
                    }
                    else
                    {
                        var newNode = new CommandTreeNode(token)
                        {
                            InGroupStartCount = unprocessedOpenParen
                        };

                        var newReference = new CommandTreeNode.Reference(newNode, false);

                        while (unprocessedOpenParen > 0)
                        {
                            stackAfterOpenParen.Push(newNode);
                            unprocessedOpenParen--;
                        }

                        curPointer.NextNodes.Add(token, newReference);
                        curPointer = newNode;
                    }
                }
            }

            if (stackAfterOpenParen.Count != 0)
            {
                throw new WrongPatternException(stackAfterOpenParen.Pop().TokenPrototype,
                                                "Количество открывающих скобок превышает количество закрывающих.");
            }

            Debug.Assert(curPointer.NextNodes.Count == 0);
            return(curPointer);
        }