protected override Node ParsingAlgorithm(string text) { Node root = null; /// Множество индексов токенов, на которых запускалось восстановление PositionsWhereRecoveryStarted = new HashSet <int>(); /// Создаём стек для уровней вложенности пар NestingStack = new Stack <int>(); /// Готовим лексер LexingStream = new ComplexTokenStream(GrammarObject, Lexer, text, Log); /// Читаем первую лексему из входного потока var token = LexingStream.GetNextToken(); /// Создаём стек Stack = new ParsingStack(); Stack.Push(0); NestingStack.Push(0); while (true) { if (token.Name == Grammar.ERROR_TOKEN_NAME) { break; } var currentState = Stack.PeekState(); if (EnableTracing && token.Name != Grammar.ERROR_TOKEN_NAME && token.Name != Grammar.ANY_TOKEN_NAME) { Log.Add(Message.Trace( $"Текущий токен: {this.GetTokenInfoForMessage(token)} | Стек: {Stack.ToString(GrammarObject)}", token.Location.Start )); } if (Table[currentState, token.Name].Count > 0) { if (token.Name == Grammar.ANY_TOKEN_NAME) { token = SkipAny(NodeGenerator.Generate(Grammar.ANY_TOKEN_NAME), true); /// Если при пропуске текста произошла ошибка, прерываем разбор if (token.Name == Grammar.ERROR_TOKEN_NAME) { break; } else { continue; } } var action = GetAction(currentState, token.Name); /// Если нужно произвести перенос if (action is ShiftAction) { var tokenNode = NodeGenerator.Generate(token.Name); tokenNode.SetValue(token.Text); tokenNode.SetLocation(token.Location.Start, token.Location.End); var shift = (ShiftAction)action; /// Вносим в стек новое состояние Stack.Push(tokenNode, shift.TargetItemIndex); NestingStack.Push(LexingStream.GetPairsCount()); if (EnableTracing) { Log.Add(Message.Trace( $"Перенос", token.Location.Start )); } token = LexingStream.GetNextToken(); } /// Если нужно произвести свёртку else if (action is ReduceAction reduce) { var parentNode = NodeGenerator.Generate(reduce.ReductionAlternative.NonterminalSymbolName); /// Снимаем со стека символы ветки, по которой нужно произвести свёртку for (var i = 0; i < reduce.ReductionAlternative.Count; ++i) { parentNode.AddFirstChild(Stack.PeekSymbol()); Stack.Pop(); NestingStack.Pop(); } currentState = Stack.PeekState(); /// Кладём на стек состояние, в которое нужно произвести переход Stack.Push( parentNode, Table.Transitions[currentState][reduce.ReductionAlternative.NonterminalSymbolName] ); NestingStack.Push(LexingStream.GetPairsCount()); if (EnableTracing) { Log.Add(Message.Trace( $"Свёртка по правилу {GrammarObject.Userify(reduce.ReductionAlternative)} -> {GrammarObject.Userify(reduce.ReductionAlternative.NonterminalSymbolName)}", token.Location.Start )); } continue; } else if (action is AcceptAction) { root = Stack.PeekSymbol(); break; } } else if (token.Name == Grammar.ANY_TOKEN_NAME) { Log.Add(Message.Warning( $"Неожиданный символ {this.GetTokenInfoForMessage(LexingStream.CurrentToken)} для состояния{Environment.NewLine}\t\t" + Table.ToString(Stack.PeekState(), null, "\t\t"), LexingStream.CurrentToken.Location.Start )); token = ErrorRecovery(); } else { /// Если встретился неожиданный токен, но он в списке пропускаемых if (GrammarObject.Options.IsSet(ParsingOption.SKIP, token.Name)) { token = LexingStream.GetNextToken(); } else { if (EnableTracing) { Log.Add(Message.Trace( $"Попытка трактовать текущий токен как начало участка, соответствующего Any", token.Location.Start )); } token = Lexer.CreateToken(Grammar.ANY_TOKEN_NAME); } } } if (root != null) { TreePostProcessing(root); if (LexingStream.CustomBlocks?.Count > 0) { var visitor = new InsertCustomBlocksVisitor(GrammarObject, LexingStream.CustomBlocks); root.Accept(visitor); root = visitor.Root; foreach (var block in visitor.CustomBlocks) { Log.Add(Message.Error( $"Блок \"{block.Start.Value[0]}\" прорезает несколько сущностей программы или находится в области, " + $"не учитываемой при синтаксическом анализе", block.Start.Location.Start )); } } } return(root); }
/// <summary> /// LL(1) разбор /// </summary> /// <returns> /// Корень дерева разбора /// </returns> protected override Node ParsingAlgorithm(string text) { /// Контроль вложенностей пар NestingLevel = new Dictionary <Node, int>(); PositionsWhereRecoveryStarted = new HashSet <int>(); /// Готовим лексер и стеки LexingStream = new ComplexTokenStream(GrammarObject, Lexer, text, Log); Stack = new Stack <Node>(); /// Кладём на стек стартовый символ var root = NodeGenerator.Generate(GrammarObject.StartSymbol); Stack.Push(NodeGenerator.Generate(Grammar.EOF_TOKEN_NAME)); Stack.Push(root); /// Читаем первую лексему из входного потока var token = LexingStream.GetNextToken(); /// Пока не прошли полностью правило для стартового символа while (Stack.Count > 0) { if (token.Name == Grammar.ERROR_TOKEN_NAME) { break; } var stackTop = Stack.Peek(); if (EnableTracing) { Log.Add(Message.Trace( $"Текущий токен: {this.GetTokenInfoForMessage(token)}\t |\t Стек: {StackString}", LexingStream.CurrentToken.Location.Start )); } /// Если символ на вершине стека совпадает с текущим токеном if (stackTop.Symbol == token.Name) { if (token.Name == Grammar.ANY_TOKEN_NAME) { token = SkipAny(NodeGenerator.Generate(Grammar.ANY_TOKEN_NAME), true); } else { var node = Stack.Pop(); node.SetLocation(token.Location.Start, token.Location.End); node.SetValue(token.Text); token = LexingStream.GetNextToken(); } continue; } /// Если на вершине стека нетерминал, выбираем альтернативу по таблице if (GrammarObject[stackTop.Symbol] is NonterminalSymbol) { var alternatives = Table[stackTop.Symbol, token.Name]; if (alternatives.Count > 0) { if (token.Name == Grammar.ANY_TOKEN_NAME) { /// Поддерживаем свойство immediate error detection для Any var runtimeFirst = Stack.Select(e => e.Symbol).ToList(); if (GrammarObject.First(runtimeFirst).Contains(Grammar.ANY_TOKEN_NAME)) { token = SkipAny(NodeGenerator.Generate(Grammar.ANY_TOKEN_NAME), true); } else { Log.Add(Message.Warning( $"Неожиданный символ {this.GetTokenInfoForMessage(LexingStream.CurrentToken)}, ожидался один из следующих символов: {String.Join(", ", runtimeFirst.Select(t => GrammarObject.Userify(t)))}", token.Location.Start )); token = ErrorRecovery(); } } else { ApplyAlternative(alternatives[0]); } continue; } } /// Если не смогли ни сопоставить текущий токен с терминалом на вершине стека, /// ни найти ветку правила для нетерминала на вершине стека if (token.Name == Grammar.ANY_TOKEN_NAME) { Log.Add(Message.Warning( GrammarObject.Tokens.ContainsKey(stackTop.Symbol) ? $"Неожиданный символ {this.GetTokenInfoForMessage(LexingStream.CurrentToken)}, ожидался символ {GrammarObject.Userify(stackTop.Symbol)}" : $"Неожиданный символ {this.GetTokenInfoForMessage(LexingStream.CurrentToken)}, ожидался один из следующих символов: {String.Join(", ", Table[stackTop.Symbol].Where(t => t.Value.Count > 0).Select(t => GrammarObject.Userify(t.Key)))}", LexingStream.CurrentToken.Location.Start )); token = ErrorRecovery(); } /// Если непонятно, что делать с текущим токеном, и он конкретный /// (не Any), заменяем его на Any else { /// Если встретился неожиданный токен, но он в списке пропускаемых if (GrammarObject.Options.IsSet(ParsingOption.SKIP, token.Name)) { token = LexingStream.GetNextToken(); } else { Log.Add(Message.Trace( $"Попытка трактовать текущий токен как начало участка, соответствующего Any", token.Location.Start )); token = Lexer.CreateToken(Grammar.ANY_TOKEN_NAME); } } } TreePostProcessing(root); if (LexingStream.CustomBlocks?.Count > 0) { var visitor = new InsertCustomBlocksVisitor(GrammarObject, LexingStream.CustomBlocks); root.Accept(visitor); root = visitor.Root; foreach (var block in visitor.CustomBlocks) { Log.Add(Message.Error( $"Блок \"{block.Start.Value[0]}\" прорезает несколько сущностей программы или находится в области, " + $"не учитываемой при синтаксическом анализе", block.Start.Location.Start )); } } return(root); }