stringtranslate.com

Левая рекурсия

В формальной теории языка информатики левая рекурсия является особым случаем рекурсии , где строка распознается как часть языка по тому факту, что она раскладывается на строку из того же языка (слева) и суффикс (справа). Например, может быть распознана как сумма, поскольку ее можно разбить на , также сумму, и , подходящий суффикс.

В терминах контекстно-свободной грамматики нетерминал является леворекурсивным, если крайний левый символ в одном из его производных является им самим (в случае прямой левой рекурсии) или может быть сделан самим собой с помощью некоторой последовательности замен (в случае косвенной левой рекурсии) .

Определение

Грамматика является леворекурсивной тогда и только тогда, когда существует нетерминальный символ , который может быть выведен в сентенциальную форму с самим собой в качестве самого левого символа. [1] Символически,

,

где обозначает операцию выполнения одной или нескольких замен, а — любая последовательность терминальных и нетерминальных символов.

Прямая левая рекурсия

Прямая левая рекурсия возникает, когда определение может быть удовлетворено только одной заменой. Она требует правила вида

где — последовательность нетерминалов и терминалов. Например, правило

напрямую леворекурсивен. Анализатор рекурсивного спуска слева направо для этого правила может выглядеть так

void Выражение () { Выражение (); совпадение ( '+' ); Термин (); }     

и такой код при выполнении впадет в бесконечную рекурсию.

Косвенная левая рекурсия

Косвенная левая рекурсия происходит, когда определение левой рекурсии удовлетворяется посредством нескольких подстановок. Она влечет за собой набор правил, следующих шаблону

где — последовательности, каждая из которых может дать пустую строку , в то время как могут быть любыми последовательностями терминальных и нетерминальных символов вообще. Обратите внимание, что эти последовательности могут быть пустыми. Вывод

затем дается как самое левое в его окончательной фразовой форме.

Использует

Левая рекурсия обычно используется как идиома для создания левоассоциативных операций : выражение a+b-c-d+eоценивается как (((a+b)-c)-d)+e. В этом случае этот порядок оценки может быть достигнут как вопрос синтаксиса с помощью трех грамматических правил

Они позволяют анализировать только тот вариант, который состоит из и , где в свою очередь состоит из и , в то время как состоит из и и т. д. a+b-c-d+e a+b-c-d ea+b-c-d a+b-c da+b-c a+b c

Удаление левой рекурсии

Левая рекурсия часто создает проблемы для парсеров, либо потому что она приводит их к бесконечной рекурсии (как в случае большинства парсеров, работающих сверху вниз ), либо потому что они ожидают правил в нормальной форме, которая запрещает ее (как в случае многих парсеров, работающих снизу вверх [ необходимо разъяснение ] ). Поэтому грамматика часто подвергается предварительной обработке для устранения левой рекурсии.

Удаление прямой левой рекурсии

Ниже приведен общий алгоритм удаления прямой левой рекурсии. Было сделано несколько улучшений этого метода. [2] Для леворекурсивного нетерминала отбросьте все правила формы и рассмотрите те, которые остались:

где:

Замените их двумя наборами производств, один набор для :

и еще один набор для свежего нетерминала (часто называемого «хвостом» или «остаком»):

Повторяйте этот процесс до тех пор, пока не останется ни одной прямой левой рекурсии.

В качестве примера рассмотрим набор правил

Это можно переписать, чтобы избежать левой рекурсии, как

Удаление всей левой рекурсии

Описанный выше процесс можно расширить, чтобы исключить всю левую рекурсию, сначала преобразовав косвенную левую рекурсию в прямую левую рекурсию на нетерминале с наибольшим номером в цикле.

Входные данные Грамматика: набор нетерминалов и их производных
Вывод: модифицированная грамматика, генерирующая тот же язык, но без левой рекурсии.
  1. Для каждого нетерминала :
    1. Повторяйте до тех пор, пока итерация не оставит грамматику неизменной:
      1. Для каждого правила , представляющего собой последовательность терминалов и нетерминалов:
        1. Если начинается с нетерминала и :
          1. Пусть будет без его руководства .
          2. Удалить правило .
          3. Для каждого правила :
            1. Добавьте правило .
    2. Удалить прямую левую рекурсию, как описано выше.

Шаг 1.1.1 сводится к расширению начального нетерминала в правой части некоторого правила , но только если . Если был одним шагом в цикле производств, приводящих к левой рекурсии, то это сократило этот цикл на один шаг, но часто ценой увеличения количества правил.

Алгоритм можно рассматривать как установление топологического порядка на нетерминалах: после этого может быть только правило , если . Обратите внимание, что этот алгоритм очень чувствителен к нетерминальному порядку; оптимизации часто фокусируются на выборе этого порядка. [ необходимо разъяснение ]

Подводные камни

Хотя указанные выше преобразования сохраняют язык, сгенерированный грамматикой, они могут изменить деревья разбора , которые свидетельствуют о распознавании строк. При соответствующем учете переписывание деревьев может восстановить оригиналы, но если этот шаг пропущен, различия могут изменить семантику разбора.

Ассоциативность особенно уязвима; левоассоциативные операторы обычно появляются в правоассоциативных расположениях в рамках новой грамматики. Например, начиная с этой грамматики:

стандартные преобразования для удаления левой рекурсии дают следующее:

Разбор строки «1 - 2 - 3» с помощью первой грамматики в анализаторе LALR (который может обрабатывать леворекурсивные грамматики) привел бы к следующему дереву разбора:

Леворекурсивный разбор двойного вычитания

Это дерево синтаксического анализа группирует термины слева, давая правильную семантику (1 - 2) - 3 .

Разбор со второй грамматикой дает

Праворекурсивный разбор двойного вычитания

что, если правильно интерпретировать, означает 1 + (-2 + (-3)) , также правильно, но менее точно соответствует вводу и гораздо сложнее для реализации для некоторых операторов. Обратите внимание, как термины справа оказываются глубже в дереве, подобно тому, как праворекурсивная грамматика расположила бы их для 1 - (2 - 3) .

Обеспечение левой рекурсии при нисходящем анализе

Формальная грамматика , содержащая левую рекурсию, не может быть проанализирована LL (k)-анализатором или другим наивным рекурсивным спусковым анализатором, если она не преобразована в слабо эквивалентную праворекурсивную форму. Напротив, левая рекурсия предпочтительнее для LALR-анализаторов , поскольку она приводит к меньшему использованию стека, чем правая рекурсия . Однако более сложные нисходящие анализаторы могут реализовывать общие контекстно-свободные грамматики с помощью сокращения. В 2006 году Фрост и Хафиз описали алгоритм, который приспосабливает неоднозначные грамматики с помощью прямых леворекурсивных правил производства . [3] Этот алгоритм был расширен до полного алгоритма синтаксического анализа для учета как косвенной, так и прямой левой рекурсии за полиномиальное время и для генерации компактных представлений полиномиального размера потенциально экспоненциального числа деревьев синтаксического анализа для высоко неоднозначных грамматик Фростом, Хафизом и Каллаганом в 2007 году. [4] Затем авторы реализовали алгоритм как набор комбинаторов синтаксического анализа, написанных на языке программирования Haskell . [5]

Смотрите также

Ссылки

  1. ^ Заметки о формальной теории языка и синтаксическом анализе на Wayback Machine (архив 2007-11-27). Джеймс Пауэр, кафедра компьютерных наук Национального университета Ирландии, Мейнут Мейнут, графство Килдэр, Ирландия.JPR02
  2. ^ Мур, Роберт С. (май 2000 г.). «Удаление левой рекурсии из контекстно-свободных грамматик» (PDF) . 6-я конференция по прикладной обработке естественного языка : 249–255.
  3. ^ Frost, R.; R. Hafiz (2006). «Новый алгоритм анализа сверху вниз для учета неоднозначности и левой рекурсии за полиномиальное время». ACM SIGPLAN Notices . 41 (5): 46–54. doi :10.1145/1149982.1149988. S2CID  8006549., доступно у автора по адресу http://hafiz.myweb.cs.uwindsor.ca/pub/p46-frost.pdf Архивировано 08.01.2015 на Wayback Machine
  4. ^ Frost, R.; R. Hafiz; P. Callaghan (июнь 2007 г.). «Modular and Efficient Top-Down Parsing for Ambiguous Left-Recursive Grammars» (PDF) . 10th International Workshop on Parsing Technologies (IWPT), ACL-SIGPARSE : 109–120. Архивировано из оригинала (PDF) 2011-05-27.
  5. ^ Frost, R.; R. Hafiz; P. Callaghan (январь 2008). "Parser Combinators for Ambiguous Left-Recursive Grammars". Практические аспекты декларативных языков (PDF) . Конспект лекций по информатике. Том 4902. С. 167–181. doi :10.1007/978-3-540-77442-6_12. ISBN 978-3-540-77441-9.

Внешние ссылки