コード例 #1
0
        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);
        }
コード例 #2
0
ファイル: Parser.cs プロジェクト: alexeyvale/SYRCoSE-2019
        /// <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);
        }