Jump to content

Разбор грамматики выражений

В информатике грамматика выражений синтаксического анализа ( PEG ) — это тип аналитической формальной грамматики , т. е. она описывает формальный язык в терминах набора правил распознавания строк на языке. Формализм был предложен Брайаном Фордом в 2004 году. [1] и тесно связан с семейством языков нисходящего синтаксического анализа, представленных в начале 1970-х годов. Синтаксически PEG также похожи на контекстно-свободные грамматики (CFG), но имеют другую интерпретацию: оператор выбора выбирает первое совпадение в PEG, тогда как в CFG оно неоднозначно. Это ближе к тому, как распознавание строк обычно выполняется на практике, например, с помощью анализатора рекурсивного спуска .

В отличие от CFG, PEG не могут быть неоднозначными ; строка имеет ровно одно допустимое дерево разбора или ни одного. Предполагается, что существуют контекстно-свободные языки, которые не могут быть распознаны PEG, но это еще не доказано. [1] PEG хорошо подходят для анализа компьютерных языков (и искусственных человеческих языков, таких как ложбан ), где множественные альтернативы интерпретации могут быть устранены локально, но вряд ли будут полезны для анализа естественных языков , где устранение неоднозначности может быть глобальным. [2]

Определение

[ редактировать ]

Выражение синтаксического анализа это своего рода шаблон, которому каждая строка может соответствовать или не соответствовать . В случае совпадения существует уникальный префикс строки (который может быть всей строкой, пустой строкой или чем-то промежуточным), который был использован выражением синтаксического анализа; этот префикс обычно считается соответствующим выражению. Однако соответствие строки выражению синтаксического анализа может (из-за предикатов просмотра вперед) зависеть от ее частей, которые идут после потребляемой части. — Язык выражений синтаксического анализа это набор всех строк, соответствующих определенному выражению синтаксического анализа. [1] : Раздел 3.4

Грамматика выражений синтаксического анализа это набор именованных выражений синтаксического анализа, которые могут ссылаться друг на друга. Эффект одной такой ссылки в выражении синтаксического анализа аналогичен тому, как если бы вместо ссылки было задано все выражение синтаксического анализа, на которое имеется ссылка. Грамматика выражений синтаксического анализа также имеет назначенное начальное выражение ; строка соответствует грамматике, если она соответствует ее начальному выражению.

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

Синтаксис

[ редактировать ]

как абстрактный , так и конкретный В литературе и в этой статье можно увидеть синтаксис выражений синтаксического анализа. Абстрактный синтаксис, по сути, представляет собой математическую формулу и в основном используется в теоретическом контексте, тогда как конкретные выражения синтаксического анализа могут использоваться непосредственно для управления синтаксическим анализатором . Первичный конкретный синтаксис определен Фордом: [1] : Рис.1 хотя многие инструменты имеют свой собственный диалект. Другие инструменты [3] может быть ближе к использованию собственной кодировки выражений синтаксического анализа абстрактного синтаксиса в качестве их конкретного синтаксиса.

Выражения атомарного анализа

[ редактировать ]

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

  "terminal" Nonterminal 'another terminal'

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

Конкретный синтаксис также имеет ряд форм для классов терминалов:

  • А . (точка) — выражение синтаксического анализа, соответствующее любому отдельному терминалу.
  • В скобках список символов. [abcde] сформируйте выражение синтаксического анализа, соответствующее одному из нумерованных символов. Как и в регулярных выражениях , эти классы также могут включать диапазоны. [0-9A-Za-z] записывается в виде дефиса с конечными точками диапазона до и после него. (В отличие от регулярных выражений, классы символов скобок не имеют ^ для отрицания; вместо этого эту цель можно получить с помощью не-предикатов.)
  • В некоторых диалектах есть дополнительные обозначения для предопределенных классов символов, таких как буквы, цифры, знаки препинания или пробелы; это снова похоже на ситуацию в регулярных выражениях.

В абстрактном синтаксисе такие формы обычно формализуются как нетерминалы, точное определение которых для краткости опущено; в Юникоде десятки тысяч символов являются буквами. И наоборот, теоретические дискуссии иногда вводят атомарный абстрактный синтаксис для понятий, которые альтернативно могут быть выражены с использованием составных выражений синтаксического анализа. Примеры этого включают:

  • пустая строка ε (как выражение синтаксического анализа оно соответствует каждой строке и не содержит символов),
  • конец ввода E (конкретный синтаксический эквивалент !.), и
  • отказ (ничего не соответствует).

В конкретном синтаксисе терминалы в кавычках и квадратных скобках имеют обратную косую черту, так что « перевод строки или возврат каретки ». можно записать [\n\r]. Аналогом абстрактного синтаксиса терминала в кавычках длиной больше единицы будет последовательность этих терминалов; "bar" то же самое, что "b" "a" "r". Основной конкретный синтаксис не придает терминалам определенного значения в зависимости от того, используют ли они одинарные или двойные кавычки, но некоторые диалекты рассматривают один из них как регистрозависимый, а другой - как регистронезависимый.

Составные выражения синтаксического анализа

[ редактировать ]

Учитывая любые существующие выражения синтаксического анализа e , e 1 и e 2 , новое выражение синтаксического анализа может быть создано с использованием следующих операторов:

  • Последовательность : е 1 е 2
  • Заказанный выбор : e 1 / e 2
  • Ноль или больше : e *
  • Один или несколько : e +
  • Необязательно : е ?
  • И-предикат : & e
  • Не-предикат : ! е
  • Группа : ( е )

Приоритеты операторов следующие, согласно Таблице 1: [1]

Оператор Приоритет
( е ) 5
и *, и +, и ? 4
& е , ! е 3
е 1 е 2 2
е1 / eе2 1

Грамматики

[ редактировать ]

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

  Identifier LEFTARROW Expression

The Identifier определяется нетерминал, а Expression — это выражение синтаксического анализа, на которое оно определено как ссылка. LEFTARROW немного различается в зависимости от диалекта, но обычно представляет собой стрелку, указывающую влево, или символ назначения, например <-, , :=, или =. Один из способов понять это — это сделать присваивание или определение нетерминала. Другой способ понять это — противопоставить стрелку, указывающую вправо →, используемую в правилах контекстно -свободной грамматики ; при анализе выражений поток информации идет от выражения к нетерминальному, а не от нетерминального к выражению.

Как математический объект, грамматика выражений синтаксического анализа представляет собой кортеж. , где - набор нетерминальных символов, - набор терминальных символов, это функция от к набору выражений синтаксического анализа на , и — это начальное выражение синтаксического анализа. Некоторые конкретные синтаксические диалекты явно дают начальное выражение: [4] но вместо этого основной конкретный синтаксис имеет неявное правило, согласно которому первый определенный нетерминал является начальным выражением.

Стоит отметить, что основной диалект конкретных грамматик выражений синтаксического анализа не имеет явного терминатора определения или разделителя между определениями, хотя принято начинать новое определение с новой строки; тот LEFTARROW следующего определения достаточно для нахождения границы, если добавить ограничение, согласно которому нетерминал в Expression не должно сопровождаться LEFTARROW. Однако некоторые диалекты могут допускать явный терминатор или прямо требовать [4] это.

Это PEG, который распознает математические формулы, применяющие пять основных операций к неотрицательным целым числам.

Expr     Sum
Sum      Product (('+' / '-') Product)*
Product  Power (('*' / '/') Power)*
Power    Value ('^' Power)?
Value    [0-9]+ / '(' Expr ')'

В приведенном выше примере терминальные символы представляют собой символы текста, представленные символами в одинарных кавычках, например: '(' и ')'. Диапазон [0-9] это сокращение для десяти символов из '0' к '9'. (Этот синтаксис диапазона аналогичен синтаксису, используемому в регулярных выражениях .) Нетерминальные символы — это символы, которые расширяются до других правил: Value , Power , Product , Sum и Expr . Обратите внимание, что правила Sum и Product не приводят к желаемой левой ассоциативности этих операций (они вообще не имеют дело с ассоциативностью, и ее необходимо обрабатывать на этапе постобработки после синтаксического анализа), а правило Power (с помощью ссылаясь на себя справа) приводит к желаемой правой ассоциативности показателя степени. Также обратите внимание, что правило типа Sum Sum (('+' / '-') Product)? (с намерением добиться левой ассоциативности) вызовет бесконечную рекурсию, поэтому его нельзя использовать на практике, даже если его можно выразить в грамматике.

Семантика

[ редактировать ]

Фундаментальное различие между контекстно-свободными грамматиками и грамматиками синтаксического анализа заключается в том, что оператор выбора PEG является упорядоченным . Если первый вариант успешен, второй вариант игнорируется. Таким образом, упорядоченный выбор не является коммутативным , в отличие от неупорядоченного выбора, как в контекстно-свободных грамматиках. Упорядоченный выбор аналогичен операторам мягкого сокращения , доступным в некоторых логического программирования языках .

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

При синтаксическом анализе грамматик выражений также добавляются синтаксические предикаты and и not . Поскольку они могут использовать произвольно сложное подвыражение для «просмотра вперед» входной строки, не потребляя ее фактически, они предоставляют мощные средства синтаксического просмотра и устранения неоднозначности, в частности, когда переупорядочение альтернатив не может указать точное желаемое дерево синтаксического анализа.

Операционная интерпретация выражений синтаксического анализа

[ редактировать ]

Каждый нетерминал в грамматике выражений синтаксического анализа по существу представляет собой функцию синтаксического анализа в анализаторе рекурсивного спуска , а соответствующее выражение синтаксического анализа представляет собой «код», содержащий эту функцию. Каждая функция синтаксического анализа концептуально принимает входную строку в качестве аргумента и возвращает один из следующих результатов:

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

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

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

Оператор последовательности e e 1 e 2 сначала вызывает e 1 , и, если e 1 завершается успешно, впоследствии вызывает e 2 для оставшейся части входной строки, не использованной 1 , и возвращает результат. Если e 1 или e 2 терпят неудачу, то выражение последовательности e 1 e 2 терпит неудачу (не потребляя никаких входных данных).

Оператор выбора если e1 / , e2 , вызывает e1 и завершается успешно e1 сначала немедленно возвращает свой результат. В противном случае, если e 1 терпит неудачу, тогда оператор выбора возвращается к исходной позиции ввода, в которой он вызвал e 1 , но затем вместо этого вызывает e 2 , возвращая e 2 результат .

Операторы ноль или более , один или более и необязательные используют ноль или более, одно или более или ноль или одно последовательные повторения своего подвыражения e соответственно. Однако, в отличие от контекстно-свободных грамматик и регулярных выражений , эти операторы всегда ведут себя жадно , потребляя как можно больше входных данных и никогда не возвращаясь назад. (Средства сопоставления регулярных выражений могут начать с жадного сопоставления, но затем вернутся и попытаются найти более короткие совпадения, если они не совпадают.) Например, выражение a* всегда будет использовать столько символов a, сколько последовательно доступно во входной строке, а выражение (a* a) всегда будет неудачным, потому что первая часть (a*) никогда не оставит никаких букв для соответствия второй части.

Выражение and-predicate & e вызывает подвыражение e , а затем завершается успешно, если e завершается успешно, и завершается неудачно, если e завершается неудачно, но в любом случае никогда не потребляет никаких входных данных .

Непредикатное выражение ! e завершается успешно, если e завершается неудачей, и терпит неудачу, если e завершается успешно, опять же в любом случае не потребляя никаких входных данных.

Больше примеров

[ редактировать ]

Следующее рекурсивное правило соответствует стандартным операторам if/then/else в стиле C таким образом, что необязательное предложение else всегда привязывается к самому внутреннему оператору if из-за неявного определения приоритета оператора '/'. (В контекстно-свободной грамматике эта конструкция дает классическую двусмысленность висячего else .)

S  'if' C 'then' S 'else' S / 'if' C 'then' S

Следующее рекурсивное правило соответствует синтаксису вложенных комментариев в стиле Паскаля: (* which can (* nest *) like this *). Напомним, что . соответствует любому отдельному символу.

C      Begin N* End
Begin  '(*'
End    '*)'
N      C / (!Begin !End .)

Выражение синтаксического анализа foo &(bar) соответствует и потребляет текст «foo», но только если за ним следует текст «bar». Выражение синтаксического анализа foo !(bar) соответствует тексту «foo», но только если за ним не следует текст «bar». Выражение !(a+ b) a соответствует одному «а», но только если он не является частью произвольно длинной последовательности букв «а», за которой следует буква «б».

Выражение синтаксического анализа ('a'/'b')* соответствует и потребляет последовательность символов a и b произвольной длины. Правило производства S 'a' ''S''? 'b' описывает простой контекстно-свободный «язык сопоставления». . Следующая грамматика выражений синтаксического анализа описывает классический неконтекстно-свободный язык. :

S  &(A 'c') 'a'+ B !.
A  'a' A? 'b'
B  'b' B? 'c'

Реализация парсеров из анализа грамматик выражений

[ редактировать ]

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

Можно добиться более высокой производительности для любой грамматики синтаксического анализа, преобразовав ее анализатор рекурсивного спуска в анализатор Packrat , который всегда работает за линейное время , ценой существенно большего требования к объему памяти. Парсер Packrat [5] это форма синтаксического анализатора, аналогичная по конструкции парсеру рекурсивного спуска, за исключением того, что во время процесса синтаксического анализа он запоминает промежуточные результаты всех вызовов взаимно рекурсивных функций синтаксического анализа, гарантируя, что каждая функция синтаксического анализа вызывается не более одного раза на заданном входе. позиция. Благодаря этой мемоизации парсер Packrat имеет возможность анализировать множество контекстно-свободных грамматик и любую грамматику синтаксических выражений (включая те, которые не представляют контекстно-свободные языки) за линейное время. Примеры мемоизированных парсеров рекурсивного спуска известны как минимум еще с 1993 года. [6] Этот анализ производительности парсера Packrat предполагает, что памяти достаточно для хранения всех запомненных результатов; на практике, если памяти недостаточно, некоторые функции синтаксического анализа, возможно, придется вызывать более одного раза в одной и той же позиции ввода, и, следовательно, синтаксический анализатор может занять больше линейного времени.

Также возможно создавать анализаторы LL и анализаторы LR на основе анализа грамматик выражений. [ нужна ссылка ] с лучшей производительностью в худшем случае, чем анализатор рекурсивного спуска без мемоизации, но при этом теряется неограниченная возможность просмотра вперед грамматического формализма. Следовательно, не все языки, которые могут быть выражены с использованием синтаксических грамматик выражений, могут быть проанализированы анализаторами LL или LR.

Восходящий анализ PEG

[ редактировать ]

И парсер пищит [7] использует динамическое программирование для применения правил PEG снизу вверх и справа налево, что является обратным обычному порядку рекурсивного спуска сверху вниз, слева направо. Синтаксический анализ в обратном порядке решает проблему левой рекурсии, позволяя использовать леворекурсивные правила непосредственно в грамматике без перезаписи в нелеворекурсивную форму, а также предоставляет синтаксическому анализатору оптимальные возможности восстановления ошибок, чего исторически оказалось трудно достичь. для парсеров рекурсивного спуска.

Преимущества

[ редактировать ]

Компиляция не требуется

[ редактировать ]

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

По сравнению с регулярными выражениями

[ редактировать ]

По сравнению с чистыми регулярными выражениями (т. е. описывающими язык, распознаваемый с помощью конечного автомата ), PEG гораздо более мощны. В частности, они могут обрабатывать неограниченную рекурсию и, таким образом, сопоставлять круглые скобки до произвольной глубины вложенности; регулярные выражения в лучшем случае могут отслеживать вложенность до некоторой фиксированной глубины, поскольку конечный автомат (имеющий конечный набор внутренних состояний) может различать только конечное число различных глубин вложенности. Если говорить более теоретически, (язык всех строк из нуля и более 's, за которыми следует же количество такое s) не является обычным языком, но легко увидеть, что это язык синтаксического анализа выражений, соответствующий грамматике

start    AB !.
AB  ('a' AB 'b')?

Здесь AB !. является начальным выражением. !. часть обеспечивает, чтобы ввод заканчивался после AB, сказав «следующего символа нет»; в отличие от регулярных выражений, которые имеют магические ограничения $ или \Z для этого выражения синтаксического анализа могут выражать конец ввода, используя только базовые примитивы.

The *, +, и ? выражений синтаксического анализа аналогичны тем, которые используются в регулярных выражениях, но разница в том, что они работают строго в жадном режиме. В конечном итоге это связано с / будучи упорядоченным выбором. Следствием этого является то, что что-то может соответствовать регулярному выражению, но не соответствовать выражению синтаксического анализа:

[ab]?[bc][cd]

является одновременно допустимым регулярным выражением и допустимым выражением синтаксического анализа. Как регулярное выражение оно соответствует bc, но как выражение синтаксического анализа оно не соответствует, потому что [ab]? будет соответствовать b, затем [bc] будет соответствовать c, не оставляя ничего для [cd], поэтому в этот момент сопоставление последовательности не удается. «Попытка еще раз» с наличием [ab]? соответствие пустой строки явно противоречит семантике выражений синтаксического анализа; это не крайний случай конкретного алгоритма сопоставления, а искомое поведение.

Даже регулярные выражения, которые зависят от недетерминизма, могут быть скомпилированы в грамматику синтаксического анализа, имея отдельный нетерминал для каждого состояния соответствующего DFA и кодируя его функцию перехода в определения этих нетерминалов —

A   'x' B / 'y' C

фактически означает «переход из состояния A в состояние B, если следующим символом является x, но в состояние C, если следующим символом является y» — но это работает, потому что недетерминизм можно устранить в области обычных языков. Он не будет использовать варианты выражений синтаксического анализа операций повторения.

По сравнению с контекстно-свободными грамматиками

[ редактировать ]

PEG можно удобно задавать в виде символов, тогда как контекстно-свободные грамматики (CFG) обычно задаются в виде токенов, что требует дополнительного этапа токенизации перед собственно синтаксическим анализом. [8] Преимущество отсутствия отдельного токенизатора заключается в том, что разные части языка (например, встроенные мини-языки ) могут легко иметь разные правила токенизации.

В строго формальном смысле PEG, скорее всего, несопоставимы с CFG, но на практике есть много вещей, которые PEG могут делать, чего не могут чистые CFG, тогда как трудно привести примеры обратного. В частности, PEG могут быть созданы для естественного разрешения неоднозначностей, таких как проблема « висячего else » в C, C++ и Java, тогда как для их разрешения на основе CFG часто требуется правило вне грамматики. Более того, любой PEG можно проанализировать за линейное время с помощью анализатора Packrat, как описано выше, тогда как анализ в соответствии с общей CFG асимптотически эквивалентен [9] к умножению логических матриц (таким образом, вероятно, между квадратичным и кубическим временем).

Одним из классических примеров формального языка, который, очевидно, не является контекстно-свободным, является язык : произвольное количество за ними следует равное количество s, за которыми, в свою очередь, следует равное количество с. Это тоже язык синтаксического анализа, которому соответствует грамматика

start  AB 'c'*
AB     'a' AB 'b' / &(BC !.)
BC     ('b' BC 'c')?

Для AB чтобы соответствовать, первый отрезок за s должно следовать равное количество с, и кроме того BC должно совпадать с местом, где переключиться на s, что означает те за ними следует равное количество с.

Недостатки

[ редактировать ]

Потребление памяти

[ редактировать ]

Разбор PEG обычно выполняется посредством разбора Packrat , который использует мемоизацию. [10] [11] чтобы исключить лишние шаги синтаксического анализа. Для синтаксического анализа Packrat требуется внутренняя память, пропорциональная общему размеру входных данных, а не глубине дерева синтаксического анализа, как в случае с парсерами LR. Является ли это существенной разницей, зависит от обстоятельств; если синтаксический анализ является услугой, предоставляемой как функция , то синтаксический анализатор будет хранить полное дерево синтаксического анализа до тех пор, пока не вернет его, и уже это дерево синтаксического анализа обычно будет иметь размер, пропорциональный общему размеру входных данных. Если вместо этого синтаксический анализ предоставляется в виде генератора , то можно обойтись сохранением в памяти только частей дерева синтаксического анализа, но осуществимость этого зависит от грамматики. Грамматика выражений синтаксического анализа может быть спроектирована так, что только после обработки всех входных данных анализатор обнаружит, что ему необходимо вернуться к началу. [12] что снова может потребовать хранения, пропорционального общему размеру входных данных.

Для рекурсивных грамматик и некоторых входных данных глубина дерева разбора может быть пропорциональна размеру входных данных. [13] поэтому и анализатор LR, и анализатор Packrat будут иметь одинаковую асимптотическую производительность в худшем случае. Однако во многих областях, например, в рукописном исходном коде, глубина вложенности выражений имеет фактически постоянную границу, совершенно независимую от длины программы, поскольку выражения, вложенные за пределы определенной глубины, имеют тенденцию подвергаться рефакторингу . Когда нет необходимости сохранять полное дерево разбора, более точный анализ будет учитывать глубину дерева разбора отдельно от входного размера. [14]

Вычислительная модель

[ редактировать ]

Чтобы достичь линейной общей сложности, хранилище, используемое для мемоизации, должно, кроме того, обеспечивать амортизированный постоянный доступ по времени к отдельным запоминаемым элементам данных. На практике это не проблема — например, это достигается с помощью хеш-таблицы динамического размера — но здесь используется арифметика указателей , поэтому предполагается наличие машины с произвольным доступом . Теоретические дискуссии о структурах данных и алгоритмах имеют негласную тенденцию предполагать более ограниченную модель (возможно, модель лямбда-исчисления , возможно, модель Scheme ), где разреженная таблица скорее должна быть построена с использованием деревьев, а доступ к элементам данных не является постоянным временем. . Традиционные алгоритмы синтаксического анализа, такие как парсер LL, это не затрагивает, но это становится наказанием для репутации парсеров Packrat: они полагаются на операции с, казалось бы, плохой репутацией.

С другой стороны, это говорит о том, что парсеры Packrat используют вычислительную мощность, легко доступную в реальных системах, которую старые алгоритмы синтаксического анализа не умеют использовать.

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

[ редактировать ]

ПЭГ называется хорошо сформированным. [1] если он не содержит леворекурсивных правил, т. е. правил, которые позволяют нетерминалу расширяться до выражения, в котором тот же нетерминал встречается в качестве самого левого символа. Для анализатора сверху вниз слева направо такие правила вызывают бесконечный регресс: анализ будет постоянно расширять один и тот же нетерминал без продвижения вперед по строке. Следовательно, чтобы разрешить синтаксический анализ Packrat, необходимо устранить левую рекурсию.

Практическая значимость

[ редактировать ]

Прямая рекурсия, будь то левая или правая, важна в контекстно-свободных грамматиках, поскольку там рекурсия — единственный способ описать повторение:

Sum    Term | Sum '+' Term | Sum '-' Term
Args   Arg | Arg ',' Args

Люди, обученные использованию контекстно-свободных грамматик, часто приходят к PEG, ожидая использовать одни и те же идиомы, но анализ выражений может выполнять повторение без рекурсии:

Sum    Term ( '+' Term / '-' Term )*
Args   Arg ( ',' Arg )*

Разница заключается в генерируемых абстрактных синтаксических деревьях : с рекурсией каждое Sum или Args может иметь не более двух детей, но при повторении их может быть сколь угодно много. Если более поздние этапы обработки требуют, чтобы такие списки дочерних элементов были преобразованы в деревья с ограниченной степенью (например, инструкции микропроцессора для сложения обычно допускают только два операнда), тогда такие свойства, как левая ассоциативность, будут применены после этапа синтаксического анализа, управляемого PEG.

Поэтому левая рекурсия практически с меньшей вероятностью создаст проблемы для анализатора PEG-packrat, чем, скажем, для контекстно-свободного анализатора LL(k), если только кто-то не настаивает на использовании контекстно-свободных идиом. Однако не все случаи рекурсии связаны с повторением.

Неповторяющаяся левая рекурсия

[ редактировать ]

Например, в приведенной выше арифметической грамматике может показаться заманчивым выразить приоритет операторов как вопрос упорядоченного выбора: Sum / Product / Value означало бы сначала попробовать просмотреть как Sum (поскольку мы анализируем сверху вниз), во-вторых, попробуйте просмотреть как Product, и только третья попытка просмотра как Value — а не через вложение определений. Эта (неправильно сформированная) грамматика стремится сохранить порядок приоритета только в одной строке:

Value    [0-9.]+ / '(' Expr ')'
Product  Expr (('*' / '/') Expr)+
Sum      Expr (('+' / '-') Expr)+
Expr     Sum / Product / Value

К сожалению, соответствие Expr требует тестирования, если Sum совпадает, при этом сопоставляя Sum требует тестирования, если Expr матчи. Поскольку термин появляется в крайнем левом положении, эти правила образуют замкнутое определение , которое невозможно разрешить. (Существуют циклические определения, которые можно разрешить, например, в исходной формулировке из первого примера, но такие определения не должны проявлять патологическую рекурсию.) Однако леворекурсивные правила всегда можно переписать, чтобы устранить левую рекурсию. [2] [15] Например, следующее леворекурсивное правило CFG:

string-of-a  string-of-a 'a' | 'a'

можно переписать в PEG с помощью оператора плюс:

string-of-a  'a'+

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

С некоторыми изменениями традиционный синтаксический анализ Packrat может поддерживать прямую левую рекурсию. [5] [16] [17] но это приводит к потере свойства синтаксического анализа линейного времени [16] что, как правило, является оправданием использования PEG и анализа пакетов в первую очередь. Только OMeta алгоритм парсинга [16] поддерживает полную прямую и косвенную левую рекурсию без дополнительной сопутствующей сложности (но опять же, за счет потери линейной временной сложности), тогда как все анализаторы GLR поддерживают левую рекурсию.

Неожиданное поведение

[ редактировать ]

Обычное первое впечатление от PEG состоит в том, что они похожи на CFG с определенными удобными функциями — операторами повторения. *+? как в регулярных выражениях и предикатах просмотра вперед &! — плюс упорядоченный выбор для устранения неоднозначности. Этого понимания может быть достаточно, если целью является создание синтаксического анализатора языка, но его недостаточно для более теоретических обсуждений вычислительной мощности синтаксического анализа выражений. В частности, недетерминизм, присущий неупорядоченному выбору. | контекстно-свободных грамматик сильно отличается от детерминированного упорядоченного выбора. /.

Проблема средней точки

[ редактировать ]

Парсеры PEG Packrat не могут распознать некоторые однозначные недетерминированные правила CFG, такие как следующие: [2]

S  'x' S 'x' | 'x'

Ни алгоритмы анализа LL(k) , ни LR(k) не способны распознать этот пример. Однако эта грамматика может использоваться обычным анализатором CFG, например алгоритмом CYK . Однако рассматриваемый язык может быть распознан всеми этими типами парсеров, поскольку на самом деле это обычный язык (строки с нечетным числом x).

Полезно выяснить, что именно делает анализатор PEG при попытке сопоставить

S  'x' S 'x' / 'x'

против струны xxxxxq. Как и ожидалось, он рекурсивно пытается сопоставить нетерминальный S по возрастанию позиции в этой строке, пока не будет провален матч против q, и после этого начинает отступать. Это происходит следующим образом:

Position:  123456
  String:  xxxxxq
 Results:       ↑ Pos.6: Neither branch of S matches
               ↑ Pos.5: First branch of S fails, second branch succeeds, yielding match of length 1.
              ↑ Pos.4: First branch of S fails, second branch succeeds, yielding match of length 1.
             ↑ Pos.3: First branch of S succeeds, yielding match of length 3.
            ↑ Pos.2: First branch of S fails, because after the S match at 3 comes a q.
              Second branch succeeds, yielding match of length 1.
           ↑ Pos.1: First branch of S succeeds, yielding match of length 3.

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

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

[ редактировать ]

Генераторы синтаксического анализатора LL(k) и LR(k) не смогут завершить работу, если входная грамматика неоднозначна. Это особенность обычного случая, когда грамматика должна быть однозначной, но она дефектна. Генератор синтаксического анализатора PEG разрешит непреднамеренные двусмысленности по принципу «раннее совпадение», которые могут быть произвольными и приводить к неожиданным результатам анализа.

Порядок продукций в грамматике PEG влияет не только на разрешение неоднозначности, но и на сопоставленный язык . Например, рассмотрим первый пример PEG в статье Форда. [1] (пример переписан в нотации pegjs.org/online и помечен и ):

  • :   A = "a" "b" / "a"
  • :   A = "a" / "a" "b"

Форд отмечает, что вторая альтернатива в последнем правиле PEG никогда не будет успешной, поскольку первый вариант всегда выбирается, если входная строка ... начинается с «а». . [1] В частности, (т. е. язык, соответствующий ) ​​включает ввод «ab», но нет. Таким образом, добавление новой опции в грамматику PEG может удалить строки из соответствующего языка, например — добавление правила к однопродукционной грамматике A = "a" "b", который содержит строку, которой не соответствует . Кроме того, построение грамматики, соответствующей из грамматик PEG и не всегда тривиальная задача. Это резко контрастирует с CFG, в которых добавление новой продукции не может удалить строки (хотя это может создать проблемы в виде двусмысленности). и (потенциально неоднозначная) грамматика для можно построить

S  start(G1) | start(G2)

Теория анализа грамматик выражений

[ редактировать ]

Открытой проблемой является предоставление конкретного примера контекстно-свободного языка, который не может быть распознан с помощью грамматики синтаксического анализа. [1] В частности, остается открытым вопрос, может ли грамматика синтаксического анализа распознавать язык палиндромов. [18]

Класс языков синтаксического анализа закрыт при пересечении и дополнении множеств, а значит, и при объединении множеств. [1] : Раздел 3.4

Неразрешимость пустоты

[ редактировать ]

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

Напомним, что пример задачи о переписке Почты состоит из списка пар строк (терминальных символов). Задача состоит в том, чтобы определить, существует ли последовательность индексов в диапазоне такой, что . Чтобы свести это к грамматике синтаксического анализа, позвольте — произвольные попарно различные одинаково длинные строки терминальных символов (уже с отдельные символы в алфавите терминальных символов, длина достаточно) и рассмотрим грамматику выражений синтаксического анализа Любая строка, совпадающая с нетерминалом имеет форму для некоторых индексов . Аналогично любая строка, совпадающая с нетерминалом имеет форму . Таким образом, любая строка, совпадающая с будет иметь форму где .

Практическое использование

[ редактировать ]
  • Python Эталонная реализация CPython представил парсер PEG в версии 3.9 в качестве альтернативы парсеру LL(1) и использует только PEG из версии 3.10. [19]

См. также

[ редактировать ]
  1. ^ Перейти обратно: а б с д и ж г час я дж Форд, Брайан (январь 2004 г.). «Разбор грамматик выражений: синтаксическая основа, основанная на распознавании» (PDF) . Материалы 31-го симпозиума ACM SIGPLAN-SIGACT по принципам языков программирования . АКМ . стр. 111–122. дои : 10.1145/964001.964011 . ISBN  1-58113-729-Х .
  2. ^ Перейти обратно: а б с Форд, Брайан (сентябрь 2002 г.). «Парсинг Packrat: простой, мощный, ленивый, линейное время, функциональная жемчужина» (PDF) . Уведомления ACM SIGPLAN . 37 (9). дои : 10.1145/583852.581483 .
  3. ^ Сиртиас, Матиас. «Пропаренный: построение правил на Java» . Проверено 13 января 2024 г.
  4. ^ Перейти обратно: а б Куприс, Андреас. «pt::peg_language — Учебник по языку PEG» . Исходный код библиотеки Tcl . Проверено 14 января 2024 г.
  5. ^ Перейти обратно: а б с Форд, Брайан (сентябрь 2002 г.). Анализ Packrat: практический алгоритм линейного времени с обратным отслеживанием (тезис). Массачусетский технологический институт . Проверено 27 июля 2007 г.
  6. ^ Мерритт, Дуг (ноябрь 1993 г.). «Прозрачный рекурсивный спуск» . Группа Usenet comp.compilers . Проверено 4 сентября 2009 г.
  7. ^ Хатчисон, Люк А.Д. (2020). «Разбор Пика: обратный анализ решает проблемы левой рекурсии и устранения ошибок». arXiv : 2005.06444 [ cs.PL ].
  8. ^ CFG можно использовать для описания синтаксиса распространенных языков программирования вплоть до уровня символов, но это довольно громоздко, поскольку стандартное правило токенизации, согласно которому токен состоит из самой длинной последовательной последовательности символов одного типа, плохо сочетается. с недетерминированной стороной CFG. Чтобы формализовать этот пробел между двумя соседними токенами, он является обязательным, если символы по обе стороны границы токена являются буквами, но необязательным, если они не являются буквами, CFG необходимо несколько вариантов большинства нетерминалов, чтобы отслеживать, какой тип символа имеет оказаться на границе. Если есть различные виды символов без пробелов, что в сумме составляет возможные варианты для каждого нетерминала — существенно раздувает грамматику.
  9. ^ Ли, Лилиан (январь 2002 г.). «Быстрый бесконтекстный анализ грамматики требует быстрого умножения булевой матрицы». Дж. АКМ . 49 (1): 1–15. arXiv : cs/0112018 . дои : 10.1145/505241.505242 .
  10. ^ Форд, Брайан. «Страница синтаксического анализа и анализа выражений Packrat» . BFord.info . Проверено 23 ноября 2010 г.
  11. ^ Джеллифф, Рик (10 марта 2010 г.). «Что такое анализатор Packrat? Что такое производные Бжозовского?» . Архивировано из оригинала 28 июля 2011 года.
  12. ^ Например, в самом конце ввода может быть директива о том, что «в этом файле запятая является десятичным разделителем , поэтому все вызовы функций f(3,14*r), которые, как вы думали, имели два аргумента? Они этого не делают. Теперь вернитесь к началу ввода и проанализируйте все еще раз». Возможно, это был бы плохой дизайн языка ввода, но дело в том, что синтаксический анализ грамматик выражений достаточно мощный, чтобы справиться с этим, исключительно с точки зрения синтаксиса.
  13. ^ например, выражение LISP (x (x (x (x....))))
  14. ^ Это похоже на ситуацию, которая возникает в графовых алгоритмах : алгоритм Беллмана-Форда и алгоритм Флойда-Уоршалла имеют одинаковое время работы ( ), если учитывать только количество вершин. Однако более точный анализ, учитывающий количество ребер как отдельный параметр, присваивает алгоритму Беллмана – Форда время , который является квадратичным для разреженных графов с .
  15. ^ Ахо, А.В.; Сетхи, Р.; Уллман, JD (1986). Составители: принципы, методы и инструменты . Бостон, Массачусетс, США: Аддисон-Уэсли Лонгман . ISBN  0-201-10088-6 .
  16. ^ Перейти обратно: а б с Варт, Алессандро; Дуглас, Джеймс Р.; Миллштейн, Тодд (январь 2008 г.). «Парсеры Packrat могут поддерживать левую рекурсию» (PDF) . Материалы симпозиума ACM SIGPLAN 2008 года по частичной оценке и манипулированию программами на основе семантики . ПЭПМ '08. АКМ . стр. 103–110. дои : 10.1145/1328408.1328424 . ISBN  9781595939777 . Проверено 2 октября 2008 г.
  17. ^ Штайнманн, Руди (март 2009 г.). «Обработка левой рекурсии в парсерах Packrat» (PDF) . n.ethz.ch. ​Архивировано из оригинала (PDF) 6 июля 2011 г.
  18. ^ ЛОФФ, Бруно; МОРЕЙРА, Нельма; РЕЙС, Рожерио (14 февраля 2020 г.). «Вычислительная мощность анализа грамматик выражений». arXiv : 1902.08272 [ cs.FL ].
  19. ^ «PEP 617 — новый парсер PEG для CPython | peps.python.org» . peps.python.org . Проверено 16 января 2023 г.
  20. ^ Иерусалимский, Роберто (10 марта 2009 г.). «Инструмент сопоставления текстовых шаблонов, основанный на анализе грамматик выражений» . Программное обеспечение: практика и опыт . 39 (3): 221–258. дои : 10.1002/сп.892 . ISSN   0038-0644 .
  21. ^ Иерусалимский, Роберто. «LPeg.re — синтаксис регулярных выражений для LPEG» . www.inf.puc-rio.br .
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 63e32c4b7b05abbb87460ecf3c702ab3__1722618720
URL1:https://arc.ask3.ru/arc/aa/63/b3/63e32c4b7b05abbb87460ecf3c702ab3.html
Заголовок, (Title) документа по адресу, URL1:
Parsing expression grammar - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)