Опубликован: 06.08.2007 | Доступ: свободный | Студентов: 1899 / 1053 | Оценка: 4.45 / 4.29 | Длительность: 18:50:00
Специальности: Программист
Лекция 4:

Лексический анализ

Функция followpos может быть вычислена также за один обход дерева снизу-вверх по таким двум правилам.

  1. Пусть n - внутренний узел с операцией \bullet (конкатенация), u и v - его потомки. Тогда для каждой позиции i, входящей в lastpos(u), добавляем к множеству значений followpos(i) множество firstpos(v).
  2. Пусть n - внутренний узел с операцией * (итерация), u - его потомок. Тогда для каждой позиции i, входящей в lastpos(u), добавляем к множеству значений followpos(i) множество firstpos(u).

Пример 3.8. Результат вычисления функции followpos для регулярного выражения из предыдущего примера приведен на рис. 3.13.

Алгоритм 3.3. Прямое построение ДКА по регулярному выражению.

Вход. Регулярное выражение r в алфавите T.

Выход. ДКА M = (Q, T, D, q0, F), такой что L(M) = L(r).

Метод. Состояния ДКА соответствуют множествам позиций.

Вначале Q и D пусты. Выполнить шаги 1-6:

(1) Построить синтаксическое дерево для пополненного регулярного выражения (r)#.

(2) Обходя синтаксическое дерево, вычислить значения функций nullable, firstpos, lastpos и followpos.

(3) Определить q0 = firstpos(root), где root - корень синтаксического дерева.

(4) Добавить q0 в Q как непомеченное состояние.

(5) Выполнить следующую процедуру:

\begin{align*}
& \text{\textbf{while} (в $Q$ есть непомеченное состояние $R$)\{} \\
& \quad \text{пометить $R$;} \\
&  \quad \text{\textbf{for} (каждого входного символа $a \in T$),} \\
&  \quad \quad \text{такого, что в $R$ имеется позиция,} \\
&  \quad \quad \; \; \text{которой соответствует $a$}\{ \\
&  \quad \text{пусть символ $a$ в $R$ соответствует позициям} \\
&  \quad \text{$p_1, \ldots, p_n$, и пусть $S= \bigcup\limits_{1\leq i\leq n} \; followpos(p_i)$;} \\
& \qquad \text{\textbf{if} ($S \neq \oslash$)\{} \\
& \qquad \quad \text{\textbf{if} ($S \notin Q$)} \\
& \qquad \qquad \text{добавить $S$ в $Q$ как непомеченное} \\
& \qquad \qquad \quad \text{состояние;} \\
& \qquad \quad \text{определить $D(R, a) = S$,} \\
& \qquad \} \\
& \quad \} \\
& \; \} \\
\end{align*}

(6) Определить F как множество всех состояний из Q, содержащих позиции, связанные с символом #.

Пример 3.9. Результат применения алгоритма 3.3 для регулярного выражения (a|b)*abb приведен на рис. 3.14.


Рис. 3.14.
Построение детерминированного конечного автомата с минимальным числом состояний

Рассмотрим теперь алгоритм построения ДКА с минимальным числом состояний, эквивалентного данному ДКА [?].

Пусть M = (Q, T, D, q0, F) - ДКА. Будем называть M всюду определенным, если D(q, a) \ne  \varnothing, для всех q \in Q и a \in T.

Лемма. Пусть M = (Q, T, D, q0, F) - ДКА, не являющийся всюду определенным. Существует всюду определенный ДКА M' , такой что L(M) = L(M').

Доказательство. Рассмотрим автомат

M^'=(Q\cup\{q^'\},T,D^',q_0,F),

где q' \notin  Q - некоторое новое состояние, а функция D' определяется следующим образом:

(1) Для всех q \in Q и a \in T, таких что D(q, a) \ne  \varnothing,, определить D'(q, a) = D(q, a).

(2) Для всех q \in Q и a \in T, таких что D(q, a) = \varnothing, определить D'(q, a) = q'.

(3) Для всех a \in T определить D'(q', a) = q'.

Легко показать, что автомат M' допускает тот же язык, что и M.

Приведенный ниже алгоритм получает на входе всюду определенный автомат. Если автомат не является всюду определенным, его можно сделать таковым на основании только что приведенной леммы.

Алгоритм 3.4.Построение ДКА с минимальным числом состояний.

Вход. Всюду определенный ДКА M = (Q, T, D, q0, F).

Выход. ДКА M' = (Q', T, D', q'_0, F'), такой что L(M) = L(M') и M' содержит наименьшее возможное число состояний.

Метод. Выполнить шаги 1-5:

(1) Построить начальное разбиение \prod множества состояний из двух групп: заключительные состояния Q и остальные Q - F, то есть \prod  = \{ F, Q - F\}.

(2) Применить к \prod следующую процедуру и получить новое разбиение \prod _{new}:

for (каждой группы  G  в П){
	разбить G на подгруппы так, чтобы
	состояния s и t из G оказались
	в одной подгруппе тогда и только тогда,
	когда для каждого входного символа a
	состояния s и t имеют переходы по a
	в состояния из одной и той же группы в П,
	заменить G в П new на множество всех
	полученных подгрупп,
}

(3) Если \prod _{new} = \prod, полагаем \prod _{res} = \prod и переходим к шагу 4, иначе повторяем шаг 2 с \prod  := \prod _{new}.

(4) \begin{align*}
& \text{Пусть $\prod\nolimits_{res} = \{G_1, \ldots , G_n\}$. Определим:} \\
& \text{$Q'=\{G_1,\ldots, G_n\}$;} \\
& \text{$q'_0=G$, где группа $G \in Q'$ такова, что $q_0 \in G$;} \\
& \text{$F=\{ G \mid\ G \in Q'$ и $G \cap F \neq \oslash$\};}\\
& \text{$D'(p',a)=q'$, если $D(p,a)=q$, где $p \in p'$ и $q \in q'$}
\end{align*}

Таким образом, каждая группа в \prod _{res} становится состоянием нового автомата M'. Если группа содержит начальное состояние автомата M, то эта группа становится начальным состоянием автомата M'. Если группа содержит заключительное состояние M, она становится заключительным состоянием M'. Отметим, что каждая группа \prod _{res} либо состоит только из состояний из F, либо не имеет состояний из F. Переходы определяются очевидным образом.

(5) Если M' имеет "мертвое"состояние, то есть состояние, которое не является допускающим и из которого нет путей в допускающие, удалить его и связанные с ним переходы из M'. Удалить из M' также все состояния, недостижимые из начального.

Пример 3.10. Результат применения алгоритма 3.4 приведен на рис. 3.15.


Рис. 3.15.