В информатике парсер Эрли — это алгоритм анализа строк , принадлежащих данному контекстно-свободному языку , хотя (в зависимости от варианта) у него могут возникнуть проблемы с некоторыми грамматиками, допускающими значение NULL . [1] Алгоритм, названный в честь его изобретателя Джея Эрли , представляет собой анализатор диаграмм , использующий динамическое программирование ; он в основном используется для синтаксического анализа в компьютерной лингвистике . Впервые оно было введено в его диссертацию [2] в 1968 году (а позже появилось в сокращенной, более разборчивой форме в журнале [3] ).
Парсеры Earley привлекательны тем, что могут анализировать все контекстно-свободные языки, в отличие от парсеров LR и LL , которые чаще используются в компиляторах , но могут обрабатывать только ограниченные классы языков. В общем случае парсер Эрли выполняется за кубическое время , где n — длина анализируемой строки, квадратичное время для однозначных грамматик [4] и линейное время для всех детерминированных контекстно-свободных грамматик . Он работает особенно хорошо, когда правила написаны леворекурсивно .
Следующий алгоритм описывает распознаватель Эрли. Распознаватель можно модифицировать для создания дерева разбора по мере распознавания, и таким образом превратить его в анализатор.
В следующих описаниях α, β и γ представляют собой любую строку терминалов /нетерминалов (включая пустую строку ), X и Y представляют собой отдельные нетерминалы, а a представляет символ терминала.
Алгоритм Эрли представляет собой алгоритм динамического программирования сверху вниз . Далее мы используем точечную нотацию Эрли: для данной продукции X → αβ обозначение X → α • β представляет состояние, в котором α уже проанализировано и ожидается β.
Позиция ввода 0 — это позиция перед вводом. Входная позиция n — это позиция после принятия n- го токена. (Неформально, входные позиции можно рассматривать как местоположения на границах токенов .) Для каждой входной позиции синтаксический анализатор генерирует набор состояний . Каждое состояние представляет собой кортеж (X → α • β, i ), состоящий из
(Первоначальный алгоритм Эрли включал просмотр состояния; более поздние исследования показали, что это мало влияет на эффективность синтаксического анализа, и впоследствии он был исключен из большинства реализаций.)
Состояние завершается, когда его текущая позиция является последней позицией правой части продукции, то есть, когда справа от точки • нет символа в визуальном представлении состояния.
Состояние, установленное во входной позиции k , называется S( k ). Анализатор заполняется S(0), состоящим только из правила верхнего уровня. Затем парсер неоднократно выполняет три операции: прогнозирование , сканирование и завершение .
Повторяющиеся состояния не добавляются в набор состояний, а только новые. Эти три операции повторяются до тех пор, пока в набор не перестанут добавляться новые состояния. Набор обычно реализуется как очередь состояний для обработки, причем выполняемая операция зависит от типа состояния.
Алгоритм принимает, если (X → γ •, 0) попадает в S( n ), где (X → γ) — правило верхнего уровня, а n — входная длина, в противном случае он отклоняет.
Адаптировано из книги «Обработка речи и языка» [5] Дэниела Джурафски и Джеймса Х. Мартина,
ОБЪЯВИТЬ МАССИВ S ; функция INIT ( слова ) S ← CREATE_ARRAY ( LENGTH ( слова ) + 1 ) for k ← от 0 до LENGTH ( слова ) do S [ k ] ← EMPTY_ORDERED_SET функция EARLEY_PARSE ( слова , грамматика ) INIT ( слова ) ADD_TO_SET (( γ → • S , 0 ) , S [ 0 ]) for k ← от 0 до LENGTH ( слова ) do для каждого состояния в S [ k ] do // S [k] может расширяться во время этого цикла, если не FINISHED ( state ) , тогда если NEXT_ELEMENT_OF ( state ) является нетерминалом , то PREDICTOR ( state , k , grammar ) // не_терминал else do SCANNER ( state , k , words ) // терминал else do КОМПЛЕТЕР ( состояние , k ) диаграмма конца конца возврата процедура PREDICTOR (( A → α• B β , j ) , k , grammar ) для каждого ( B → γ ) в GRAMMAR_RULES_FOR ( B , grammar ) do ADD_TO_SET (( B → •γ , k ) , S [ k ]) end процедура СКАНЕР (( A → α• a β , j ) , k , слова ) если j < ДЛИНА ( слова ) и a ⊂ ЧАСТИ_РЕЧИ ( слова [ k ]) , то ADD_TO_SET (( A → α a •β , j ) , S [ k + 1 ]) конец процедура COMPLETER (( B → γ• , x ) , k ) для каждого ( A → α• B β , j ) в S [ x ] do ADD_TO_SET (( A → α B •β , j ) , S [ k ]) конец
Рассмотрим следующую простую грамматику для арифметических выражений:
<P> ::= <S> # правило запуска<S> ::= <S> "+" <M> | <М><M> ::= <M> "*" <T> | <Т><T> ::= "1" | «2» | «3» | "4"
С вводом:
2 + 3 * 4
Это последовательность наборов состояний:
Состояние (P → S •, 0) представляет собой завершенный синтаксический анализ. Это состояние также появляется в S(3) и S(1), которые являются полными предложениями.
В диссертации Эрли [6] кратко описан алгоритм построения деревьев разбора путем добавления набора указателей от каждого нетерминала в элементе Эрли обратно к элементам, которые привели к его распознаванию. Но Томита заметил [7] , что при этом не учитываются отношения между символами, поэтому если мы рассмотрим грамматику S → SS | b и строку bbb, он только отмечает, что каждому S может соответствовать один или два b, и, таким образом, создает ложные выводы для bb и bbbb, а также два правильных вывода для bbb.
Другой метод [8] заключается в построении леса синтаксического анализа по ходу дела, дополняя каждый элемент Эрли указателем на узел общего упакованного леса синтаксического анализа (SPPF), помеченный тройкой (s, i, j), где s — символ или Элемент LR(0) (продукционное правило с точкой), а i и j обозначают часть входной строки, полученную этим узлом. Содержимое узла представляет собой либо пару дочерних указателей, дающих одно производное, либо список «упакованных» узлов, каждый из которых содержит пару указателей и представляет одно производное. Узлы SPPF уникальны (есть только один с заданной меткой), но могут содержать более одного вывода для неоднозначного анализа. Таким образом, даже если операция не добавляет элемент Эрли (поскольку он уже существует), она все равно может добавить производный элемент в лес синтаксического анализа элемента.
Узлы SPPF никогда не помечаются завершенным элементом LR(0): вместо этого они помечаются символом, который создается таким образом, что все производные элементы объединяются под одним узлом независимо от того, из какого альтернативного производства они происходят.
Филипп Маклин и Р. Найджел Хорспул в своей статье «Быстрый анализатор Эрли» сочетают анализ Эрли с анализом LR и достигают улучшения на порядок.