예제 #1
0
        private IToken SkipAny(Node anyNode, bool enableRecovery)
        {
            var nestingCopy = LexingStream.GetPairsState();
            var token       = LexingStream.CurrentToken;
            var tokenIndex  = LexingStream.CurrentIndex;
            var rawActions  = Table[Stack.PeekState(), Grammar.ANY_TOKEN_NAME];

            if (EnableTracing)
            {
                Log.Add(Message.Trace(
                            $"Инициирован пропуск Any | Стек: {Stack.ToString(GrammarObject)} | Состояние: {Environment.NewLine}\t\t"
                            + Table.ToString(Stack.PeekState(), null, "\t\t"),
                            token.Location.Start
                            ));
            }

            /// Пока по Any нужно производить свёртки (ячейка таблицы непуста и нет конфликтов)
            while (rawActions.Count == 1 && rawActions.First() is ReduceAction)
            {
                var reduce     = (ReduceAction)rawActions.First();
                var parentNode = NodeGenerator.Generate(reduce.ReductionAlternative.NonterminalSymbolName);

                /// Снимаем со стека символы ветки, по которой нужно произвести свёртку
                for (var i = 0; i < reduce.ReductionAlternative.Count; ++i)
                {
                    parentNode.AddFirstChild(Stack.PeekSymbol());
                    Stack.Pop();
                    NestingStack.Pop();
                }

                /// Кладём на стек состояние, в которое нужно произвести переход
                Stack.Push(
                    parentNode,
                    Table.Transitions[Stack.PeekState()][reduce.ReductionAlternative.NonterminalSymbolName]
                    );
                NestingStack.Push(LexingStream.GetPairsCount());

                rawActions = Table[Stack.PeekState(), Grammar.ANY_TOKEN_NAME];
            }

            /// Берём опции из нужного вхождения Any
            var marker = Table.Items[Stack.PeekState()].First(i => i.Next == Grammar.ANY_TOKEN_NAME);

            anyNode.Options = marker.Alternative[marker.Position].Options;

            /// Производим перенос
            var shift = (ShiftAction)rawActions.Where(a => a is ShiftAction).Single();

            /// Вносим в стек новое состояние
            Stack.Push(anyNode, shift.TargetItemIndex);
            NestingStack.Push(LexingStream.GetPairsCount());

            if (EnableTracing)
            {
                Log.Add(Message.Trace(
                            $"Поиск окончания последовательности, соответствующей Any | Стек: {Stack.ToString(GrammarObject)} | Состояние: {Environment.NewLine}\t\t"
                            + Table.ToString(Stack.PeekState(), null, "\t\t"),
                            token.Location.Start
                            ));
            }

            var stopTokens  = GetStopTokens(anyNode.Options, Stack.PeekState());
            var ignorePairs = anyNode.Options.AnyOptions.ContainsKey(AnyOption.IgnorePairs);

            var startLocation = anyNode.Location?.Start
                                ?? token.Location.Start;
            var endLocation = anyNode.Location?.End;
            var anyLevel    = LexingStream.GetPairsCount();

            /// Пропускаем токены, пока не найдём тот, для которого
            /// в текущем состоянии нужно выполнить перенос или свёртку
            while (!stopTokens.Contains(token.Name) &&
                   (ignorePairs || LexingStream.CurrentTokenDirection != Direction.Up) &&
                   !anyNode.Options.Contains(AnyOption.Avoid, token.Name) &&
                   token.Name != Grammar.EOF_TOKEN_NAME &&
                   token.Name != Grammar.ERROR_TOKEN_NAME)
            {
                anyNode.Value.Add(token.Text);
                endLocation = token.Location.End;

                if (ignorePairs)
                {
                    token = LexingStream.GetNextToken();
                }
                else
                {
                    token = LexingStream.GetNextToken(anyLevel, out List <IToken> skippedBuffer);

                    if (skippedBuffer.Count > 0)
                    {
                        anyNode.Value.AddRange(skippedBuffer.Select(t => t.Text));
                        endLocation = skippedBuffer.Last().Location.End;
                    }
                }
            }

            if (endLocation != null)
            {
                anyNode.SetLocation(startLocation, endLocation);
            }

            if (token.Name == Grammar.ERROR_TOKEN_NAME)
            {
                return(token);
            }

            /// Если дошли до конца входной строки, и это было не по плану
            if (!stopTokens.Contains(token.Name))
            {
                if (enableRecovery)
                {
                    var message = Message.Trace(
                        $"Ошибка при пропуске {Grammar.ANY_TOKEN_NAME}: неожиданный токен {GrammarObject.Userify(token.Name)}, ожидался один из токенов {String.Join(", ", stopTokens.Select(t => GrammarObject.Userify(t)))}",
                        token.Location.Start
                        );

                    if (GrammarObject.Options.IsSet(ParsingOption.RECOVERY))
                    {
                        ++Statistics.RecoveryTimesAny;
                        Statistics.LongestRollback =
                            Math.Max(Statistics.LongestRollback, LexingStream.CurrentIndex - tokenIndex);

                        message.Type = MessageType.Warning;
                        Log.Add(message);

                        LexingStream.MoveTo(tokenIndex, nestingCopy);

                        return(ErrorRecovery(stopTokens,
                                             anyNode.Options.Contains(AnyOption.Avoid, token.Name) ? token.Name : null));
                    }
                    else
                    {
                        message.Type = MessageType.Error;
                        Log.Add(message);
                        return(Lexer.CreateToken(Grammar.ERROR_TOKEN_NAME));
                    }
                }
                else
                {
                    Log.Add(Message.Error(
                                $"Ошибка при пропуске {Grammar.ANY_TOKEN_NAME} в процессе восстановления: неожиданный токен {GrammarObject.Userify(token.Name)}, ожидался один из токенов {String.Join(", ", stopTokens.Select(t => GrammarObject.Userify(t)))}",
                                token.Location.Start
                                ));

                    return(Lexer.CreateToken(Grammar.ERROR_TOKEN_NAME));
                }
            }

            return(token);
        }
예제 #2
0
        /// <summary>
        /// Пропуск токенов в позиции, задаваемой символом Any
        /// </summary>
        /// <returns>
        /// Токен, найденный сразу после символа Any
        /// </returns>
        private IToken SkipAny(Node anyNode, bool enableRecovery)
        {
            var nestingCopy = LexingStream.GetPairsState();
            var tokenIndex  = LexingStream.CurrentIndex;
            var token       = LexingStream.CurrentToken;

            var stackTop = Stack.Peek();

            if (EnableTracing)
            {
                Log.Add(Message.Trace(
                            $"Инициирован пропуск Any\t |\t Стек: {StackString}",
                            token.Location.Start
                            ));
            }

            /// Пока по Any нужно раскрывать очередной нетерминал
            while (GrammarObject[stackTop.Symbol] is NonterminalSymbol)
            {
                ApplyAlternative(Table[stackTop.Symbol, Grammar.ANY_TOKEN_NAME][0]);
                stackTop = Stack.Peek();
            }

            /// В итоге первым терминалом, который окажется на стеке, должен быть Any
            /// Подменяем свежесгенерированный узел для Any на переданный извне
            anyNode.Options = stackTop.Options.Clone();
            var anyIndex = stackTop.Parent.Children.IndexOf(stackTop);

            stackTop.Parent.Children.RemoveAt(anyIndex);
            stackTop.Parent.InsertChild(anyNode, anyIndex);
            Stack.Pop();

            if (EnableTracing)
            {
                Log.Add(Message.Trace(
                            $"Поиск окончания последовательности, соответствующей Any\t |\t Стек: {StackString}",
                            token.Location.Start
                            ));
            }

            var stopTokens  = GetStopTokens(anyNode.Options, Stack.Select(n => n.Symbol));
            var ignorePairs = anyNode.Options.AnyOptions.ContainsKey(AnyOption.IgnorePairs);

            /// Если Any непустой (текущий токен - это не токен,
            /// который может идти после Any)
            if (!stopTokens.Contains(token.Name))
            {
                /// Проверка на случай, если допропускаем текст в процессе восстановления
                if (anyNode.Location == null)
                {
                    anyNode.SetLocation(token.Location.Start, token.Location.End);
                }

                /// Смещение для участка, подобранного как текст
                var endLocation = token.Location.End;
                var anyLevel    = LexingStream.GetPairsCount();

                while (!stopTokens.Contains(token.Name) &&
                       (ignorePairs || LexingStream.CurrentTokenDirection != Direction.Up) &&
                       !anyNode.Options.Contains(AnyOption.Avoid, token.Name) &&
                       token.Name != Grammar.EOF_TOKEN_NAME &&
                       token.Name != Grammar.ERROR_TOKEN_NAME)
                {
                    anyNode.Value.Add(token.Text);
                    endLocation = token.Location.End;

                    if (ignorePairs)
                    {
                        token = LexingStream.GetNextToken();
                    }
                    else
                    {
                        token = LexingStream.GetNextToken(anyLevel, out List <IToken> skippedBuffer);

                        /// Если при пропуске до токена на том же уровне
                        /// пропустили токены с более глубокой вложенностью
                        if (skippedBuffer.Count > 0)
                        {
                            anyNode.Value.AddRange(skippedBuffer.Select(t => t.Text));
                            endLocation = skippedBuffer.Last().Location.End;
                        }
                    }
                }

                anyNode.SetLocation(anyNode.Location.Start, endLocation);

                if (token.Name == Grammar.ERROR_TOKEN_NAME)
                {
                    return(token);
                }

                if (!stopTokens.Contains(token.Name))
                {
                    var message = Message.Trace(
                        $"Ошибка при пропуске {Grammar.ANY_TOKEN_NAME}: неожиданный токен {GrammarObject.Userify(token.Name)}, ожидался один из следующих символов: { String.Join(", ", stopTokens.Select(t => GrammarObject.Userify(t))) }",
                        token.Location.Start
                        );

                    message.Type = enableRecovery ? MessageType.Warning : MessageType.Error;
                    Log.Add(message);

                    if (enableRecovery)
                    {
                        ++Statistics.RecoveryTimesAny;
                        Statistics.LongestRollback =
                            Math.Max(Statistics.LongestRollback, LexingStream.CurrentIndex - tokenIndex);

                        LexingStream.MoveTo(tokenIndex, nestingCopy);
                        anyNode.Reset();
                        ///	Возвращаем узел обратно на стек
                        Stack.Push(anyNode);

                        return(ErrorRecovery(stopTokens,
                                             anyNode.Options.Contains(AnyOption.Avoid, token.Name) ? token.Name : null));
                    }
                    else
                    {
                        return(Lexer.CreateToken(Grammar.ERROR_TOKEN_NAME));
                    }
                }
            }

            return(token);
        }