Определения
Определение: |
Контекстно-свободная грамматика [math] G = \langle N, \Sigma, P, S \rangle[/math] называется самоприменимой, если [math] \exists A \in N: A \Rightarrow^* \alpha A \beta[/math], [math] \alpha \neq \varepsilon \land \beta \neq \varepsilon [/math] . |
Определение: |
Нетерминал [math] A \in N[/math] в грамматике [math] G = \langle N, \Sigma, P, S \rangle[/math] называется рекурсивным, если [math] \exists \alpha,\beta \in (\Sigma \cup N)^* : A \Rightarrow^* \alpha A \beta[/math] . |
Определение: |
Нетерминалы [math] A,B \in N[/math] в грамматике [math] G = \langle N, \Sigma, P, S \rangle[/math] называются взаимно рекурсивными, если [math] \exists \alpha_1,\beta_1,\alpha_2,\beta_2 \in (\Sigma \cup N)^* : A \Rightarrow^* \alpha_1 B \beta_1 \land B \Rightarrow^* \alpha_2 A \beta_2[/math] . |
Алгоритм преобразования грамматики в конечный автомат
Лемма: |
Не самоприменимая контекстно-свободная грамматика генерирует регулярный язык. |
Доказательство: |
[math]\triangleright[/math] |
В качестве конструктивного доказательства, мы приведем алгоритм построения конечного автомата по грамматике. |
[math]\triangleleft[/math] |
Идея алгоритма
Пусть, [math] N^* [/math] множество рекурсивных терминалов из [math] N [/math].
Пусть, [math] P = \{N_1,N_2,...,N_K\} [/math] разбиение [math] N^*[/math] на [math] k [/math] дизъюнктных множеств взаимно рекурсивных терминалов,
[math] N_1 \cup N_2 \cup ... \cup N_k = N^* \land \forall i N_i \neq \emptyset [/math].
Ввведем функцию [math] recursive(N_i): P \rightarrow \{left, right, self, cycle\} [/math]:
function IsLeftType([math]N_i[/math])
return [math] \exists (A \Rightarrow \alpha B \beta) \in P[ A \in N_i \land B \in N_i \land \alpha \neq \varepsilon ][/math]
function IsRightType([math]N_i[/math])
return [math] \exists (A \Rightarrow \alpha B \beta) \in P[ A \in N_i \land B \in N_i \land \beta \neq \varepsilon ][/math]
function recursive ([math]N_i[/math]):
if !IsLeftType([math]N_i[/math]) && IsRihtType([math]N_i[/math])
return left;
if IsLeftType([math]N_i[/math]) && !IsRihtType([math]N_i[/math])
return right;
if (IsLeftType([math]N_i[/math]) && IsRihtType([math]N_i[/math])
return self;
if !IsLeftType([math]N_i[/math]) && !IsRihtType([math]N_i[/math])
return cyclic;
Заметим, что [math] \forall i [/math] [math]recursive(N_i) \neq self [/math], т.к грамматика не самоприменима.
В основе алгоритма будет рекурсивный обход грамматики во все стороны. Спускаемся по грамматике до тех пор не приходим в терминал или символ алфавита:
- символ алфавит или [math] /varepsilon [/math] — добовляем новое правило в автомат
- нерекурсивный нетерминал — запускаемся от всех правых частей правил, который терминал порождает
- рекурсивный терминал — в зависимости от типа рекурсивного нетерминала, продолжаем рекурсию (будет ясно из пседокода)
Псевдокод
[math]Q[/math] — множество состояний ДКА.
[math]\Delta[/math] — множество переходов ДКА.
[math]T[/math] — множество допускающих состояний.
function createFA(G) // [math] G = \langle N, \Sigma, P, S \rangle[/math]
[math]\mathtt{Q} \leftarrow \varnothing[/math]
[math]\Delta \leftarrow \varnothing [/math]
s = createState
f = createState
[math]F \leftarrow \{f\} [/math]
return makeFA (s,S,f)
function makeFA (q0,a,q1)
if a == [math] \varepsilon [/math] || a [math] \in \Sigma[/math] // пришли в лист дерева разбора
[math] \Delta = \Delta \cup \{(q_0,a,q_1)\} [/math]
return
if a == [math]X\beta[/math] where [math] X \in (N \cup \Sigma) \land \beta \in (N \cup \Sigma)^* \land |\beta| \gt 0 [/math]
q = createState
makeFA ([math]q_0,X,q_1[/math])
makeFA ([math]q, \beta, q_1 [/math])
return
if exist [math] N_i [/math] where [math] a \in N_i [/math]
foreach b in [math]N_i[/math]
[math]q_b[/math] = createState
if recursive([math] N_i [/math]) == left
foreach C in [math]N_i[/math] where [math] C \rightarrow X_1...X_m \land X_1,...X_m \neq N_i [/math]
makeFA ([math]q_0, X_1 \cdots X_m, q_C[/math])
foreach C,D in [math]N_i[/math] where [math] C \rightarrow DX_1...X_m \land X_1,...X_m \neq N_i [/math]
makeFA ([math]q_D, X_1 \cdots X_m, q_C[/math])
[math] \Delta = \Delta \cup \{(q_a,\varepsilon,q_1)\} [/math]
else // рекурсивный нетерминал rihgt или self
foreach C in [math]N_i[/math] where [math] C \rightarrow X_1...X_m \land X_1,...X_m \neq N_i [/math]
makeFA ([math]q_C, X_1 \cdots X_m, q_1[/math])
foreach C,D in [math]N_i[/math] where [math] C \rightarrow DX_1...X_m \land X_1,...X_m \neq N_i [/math]
makeFA ([math]q_D, X_1 \cdots X_m, q_C[/math])
[math] \Delta = \Delta \cup \{(q_0, \varepsilon ,q_a)\} [/math]
return
foreach p in [math]P[/math] where p == [math] a \rightarrow \beta [/math]
makeFA ([math] q_0, \beta, q_1 [/math])