You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: tex/GLL-based_CFPQ.tex
+14-14Lines changed: 14 additions & 14 deletions
Original file line number
Diff line number
Diff line change
@@ -8,11 +8,11 @@ \section{Рекурсивный спуск}
8
8
9
9
Идея рекурсивного спуска основана на использовании программного стека вызовов в качестве стека магазинного автомата. Достигается это следующим образом.
10
10
\begin{itemize}
11
-
\item Для каждого нетерминала создаётся функция, принимающая ещё не обработанный остаток строки и возвращающая пару: результат вывода префикса данной строки из соответствующего нетерминала и не обработанный остаток строки. В случае распзнователя результат вывода --- логическое значение (выводится/не выводится).
11
+
\item Для каждого нетерминала создаётся функция, принимающая ещё не обработанный остаток строки и возвращающая пару: результат вывода префикса данной строки из соответствующего нетерминала и не обработанный остаток строки. В случае распознавателя результат вывода --- логическое значение (выводится/не выводится).
12
12
\item Каждая такая функция реализовывает обработку цепочки согласно правым частям правил для соответствующих нетерминалов: считывание символа входа при обработке терминального символа, вызов соответствующей функции при обработке нетерминального.
13
13
\end{itemize}
14
14
15
-
У твкого подхода есть два ограничения:
15
+
У такого подхода есть два ограничения:
16
16
\begin{enumerate}
17
17
\item Не работает с леворекурсивными грамматиками, грамматиками, в которых вывод может принимать следующий вид:
18
18
$$
@@ -23,7 +23,7 @@ \section{Рекурсивный спуск}
23
23
24
24
\begin{example}
25
25
26
-
Постороим функцию рекурсивного спуска для продукции $S \rightarrow aSbS \mid\varepsilon$.
26
+
Построим функцию рекурсивного спуска для продукции $S \rightarrow aSbS \mid\varepsilon$.
Пусть $G = \langle N, \Sigma, P, S \rangle$~--- КС-грамматика. Множество $\first[k]$ определено для сентециальной формы $\alpha$ следующим образом:
109
+
Пусть $G = \langle N, \Sigma, P, S \rangle$~--- КС-грамматика. Множество $\first[k]$ определено для сентенциальной формы $\alpha$ следующим образом:
110
110
\[\first[k](\alpha) = \{\omega\in\Sigma^* \mid\alpha\derives{} \omega\text{ и } |\omega| < k \text{ либо } \exists\beta: \alpha\derives{} \omega\beta\text{ и } |\omega| = k \}
111
111
\]
112
112
, где $\alpha, \beta\in (N \cup\Sigma)^*.$
113
113
\end{definition}
114
114
115
115
\begin{definition}
116
-
Пусть $G = \langle N, \Sigma, P, S \rangle$~--- КС-грамматика. Множество $\follow[k]$ определено для сентециальной формы $\beta$ следующим образом:
116
+
Пусть $G = \langle N, \Sigma, P, S \rangle$~--- КС-грамматика. Множество $\follow[k]$ определено для сентенциальной формы $\beta$ следующим образом:
117
117
\[\follow[k](\beta) = \{\omega\in\Sigma^* \mid\exists\gamma, \alpha: S \derives{} \gamma\beta\alpha\text{ и } \omega\in\first[k](\alpha) \}\]
Интерпретатор автомата принимает входную строку и построенную управляющую таблицу и работает следующим образом.
205
205
В каждый момент времени конфигурация автомата это позиция во входной строке и стек.
206
-
В начальный момент времени стэк пуст, а позиция во входной строке соответствует её началу.
207
-
На певом шаге в стек добавляются последовательно сперва симаол концы строки, затем стартовый нетерминал.
206
+
В начальный момент времени стек пуст, а позиция во входной строке соответствует её началу.
207
+
На первом шаге в стек добавляются последовательно сперва символ концы строки, затем стартовый нетерминал.
208
208
На каждом шаге анализируется существующая конфигурация и совершается одно из действий.
209
209
\begin{itemize}
210
210
\item Если текущая позиция --- конец строки и вершина стека --- символ конца строки, то успешно завершаем разбор.
211
-
\item Если текушая вершина стека --- терминал, то проверяем, что позиция в строке соответствует этому терминалу. Если да, то снимаем элемент со стека, сдвигаем позицию на единицу и продолжаем разбор. Иначе завершаем разбор с ошибкой.
212
-
\item Если текущая врешина стека --- нетерминал $N_i$ и текущий входной символ $t_j$, то ищем в управляющей таблице ячейку с координатами $(N_i, t_j)$ и записываем на стек содержимое этой ячейки.
211
+
\item Если текущая вершина стека --- терминал, то проверяем, что позиция в строке соответствует этому терминалу. Если да, то снимаем элемент со стека, сдвигаем позицию на единицу и продолжаем разбор. Иначе завершаем разбор с ошибкой.
212
+
\item Если текущая вершина стека --- нетерминал $N_i$ и текущий входной символ $t_j$, то ищем в управляющей таблице ячейку с координатами $(N_i, t_j)$ и записываем на стек содержимое этой ячейки.
Данное семейство всё так же не работает с леворекурсивными грамматиками и с неоднозначными грамматиками.
400
400
401
401
Таким образом, по некоторым граммтикам можно построить LL(k) анализатор (назовём их LL(k) граммтиками), но не по всем.
402
-
С левой рекурсией, конечно, можно бороться, так как существуют алгоритмы устранения левой и скрытой левой рекурсии, а вот с неодносзначностями ничего не поделаешь.
402
+
С левой рекурсией, конечно, можно бороться, так как существуют алгоритмы устранения левой и скрытой левой рекурсии, а вот с неоднозначностями ничего не поделаешь.
Основанный на нисходящем анализе алгоритма поиска путей с контекстно-свободными ограничениями имеет следующие особенности.
597
597
\begin{enumerate}
598
598
\item Необходимо явно задавать начальную вершину, поэтому хорошо подходит для задач поиска путей с одним источником (single-source) или с небольшим количеством источников. Для поиска путей между всеми парами вершин необходимо явным образом все указать стартовыми.
599
-
\item Является направленным сверху вниз --- обходит граф последовательно начиная с указанной стартовой вершины и строит вывод, начиная со стартового нетерминала. Как следствие, в отличие от алгоритмов на основе линейной алгебры и Хеллингса, обойдёт только подграф, необходимый для построения ответа. В среднем это меньше, чем весь граф, который обрабанывается другими алгоритмами.
599
+
\item Является направленным сверху вниз --- обходит граф последовательно начиная с указанной стартовой вершины и строит вывод, начиная со стартового нетерминала. Как следствие, в отличие от алгоритмов на основе линейной алгебры и Хеллингса, обойдёт только подграф, необходимый для построения ответа. В среднем это меньше, чем весь граф, который обрабатывается другими алгоритмами.
600
600
\item Естественным образом строит множество путей в виде сжатого леса разбора.
601
-
\item Использует существенно более тяжеловесные стуктуры данных и плохо распараллеливается (на практике). Как следствие, при решении задачи досижимости для всех пар путей проигрывает алгоритмам на основе линейной алгебры.
601
+
\item Использует существенно более тяжеловесные стуктуры данных и плохо распараллеливается (на практике). Как следствие, при решении задачи достижимости для всех пар путей проигрывает алгоритмам на основе линейной алгебры.
602
602
\end{enumerate}
603
603
604
604
Частным случаем применения задачи КС достижимости является синтаксический анализ с неоднозначной токенизацией, то есть ситуацией, когда несколько пересекающихся подстрок во входной строке символов могут задавать разные лексические единицы и не возможно сделать однозначный выбор на этапе лексического анализа.
В таком случае на вход синтаксическому анализатору можно подать DAG, содержащий все возможные варианты токенизации. Для нашего примера он может выглядить следующим образом:
612
+
В таком случае на вход синтаксическому анализатору можно подать DAG, содержащий все возможные варианты токенизации. Для нашего примера он может выглядеть следующим образом:
Далее будем проверять наличие пути из старовой (нулевой) вершины в конечную (соответствующую концу строки). Если таких путей оказалось несколько, то нужны дополнительные средства для выбора нужного дерева разбора. Даннаяя идея рассматривается в работе~\cite{10.1145/3357766.3359532}.
636
+
Далее будем проверять наличие пути из старовой (нулевой) вершины в конечную (соответствующую концу строки). Если таких путей оказалось несколько, то нужны дополнительные средства для выбора нужного дерева разбора. Данная идея рассматривается в работе~\cite{10.1145/3357766.3359532}.
637
637
638
638
Напоследок сделаем небольшое замечание об эффективной реализации: в качестве рабочего множества $ R $ можно использовать несколько различных структур данных и, как правило, выбирают очередь. Однако иногда (в особенности для графов) лучше использовать стек дескрипторов, так как в этом случае выше локальность данных --- мы кладём пачку дескрипторов, соответствующих исходящим рёбрам. И если граф представлен списком смежности, то исходящие будут храниться рядом и их лучше обработать сразу.
0 commit comments