/// <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; }
/// <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); }