Построение FIRST и FOLLOW — различия между версиями
Shersh (обсуждение | вклад) (→Построение FOLLOW) |
Shersh (обсуждение | вклад) |
||
Строка 7: | Строка 7: | ||
Для построения <tex> \mathrm{FIRST} </tex> воспользуемся несколькими леммами, которые следуют прямо из определения. Пусть <tex> \alpha, \beta </tex> {{---}} цепочки из терминалов и нетерминалов, <tex> c </tex> {{---}} символ из алфавита. | Для построения <tex> \mathrm{FIRST} </tex> воспользуемся несколькими леммами, которые следуют прямо из определения. Пусть <tex> \alpha, \beta </tex> {{---}} цепочки из терминалов и нетерминалов, <tex> c </tex> {{---}} символ из алфавита. | ||
{{Лемма | {{Лемма | ||
− | |id=lemmafirst1 | + | |id=lemmafirst1 |
|author=1 | |author=1 | ||
|statement=<tex> \mathrm{FIRST}(\alpha \beta) = \mathrm{FIRST}(\alpha) \cup (\mathrm{FIRST}(\beta)\ \mathrm{if}\ \varepsilon \in \mathrm{FIRST}(\alpha)) </tex> | |statement=<tex> \mathrm{FIRST}(\alpha \beta) = \mathrm{FIRST}(\alpha) \cup (\mathrm{FIRST}(\beta)\ \mathrm{if}\ \varepsilon \in \mathrm{FIRST}(\alpha)) </tex> | ||
Строка 13: | Строка 13: | ||
Данная лемма означает, что в множество <tex> \mathrm{FIRST} </tex> правила <tex> A \to X_1 X_2 \dots X_k </tex>, где <tex> X_i,\ (1 \leqslant i \leqslant k) </tex> {{---}} произвольный терминал или нетерминал, {{---}} нужно добавить <tex> \mathrm{FIRST}(X_i) </tex>, если для всех <tex> 1 \leqslant j < i </tex> верно, что <tex> X_j \Rightarrow^* \varepsilon </tex>. | Данная лемма означает, что в множество <tex> \mathrm{FIRST} </tex> правила <tex> A \to X_1 X_2 \dots X_k </tex>, где <tex> X_i,\ (1 \leqslant i \leqslant k) </tex> {{---}} произвольный терминал или нетерминал, {{---}} нужно добавить <tex> \mathrm{FIRST}(X_i) </tex>, если для всех <tex> 1 \leqslant j < i </tex> верно, что <tex> X_j \Rightarrow^* \varepsilon </tex>. | ||
{{Лемма | {{Лемма | ||
− | |id=lemmafirst2 | + | |id=lemmafirst2 |
|author=2 | |author=2 | ||
|statement= | |statement= | ||
Строка 33: | Строка 33: | ||
</code> | </code> | ||
{{Утверждение | {{Утверждение | ||
− | |id=proposalfirstcorrect | + | |id=proposalfirstcorrect |
|statement=Приведённый алгоритм правильно строит множество <tex> \mathrm{FIRST} </tex> для данной грамматики. | |statement=Приведённый алгоритм правильно строит множество <tex> \mathrm{FIRST} </tex> для данной грамматики. | ||
|proof= | |proof= | ||
Строка 56: | Строка 56: | ||
}} | }} | ||
== Построение FOLLOW == | == Построение FOLLOW == | ||
− | { | + | Сформулируем похожие леммы для построения <tex> \mathrm{FOLLOW} </tex>. |
+ | {{Лемма | ||
+ | |id=lemmafollow1 | ||
+ | |author=1 | ||
+ | |statement=<tex> \mathrm{FOLLOW}(B) = </tex> | ||
+ | }} | ||
+ | |||
+ | == Пример == | ||
== См. также == | == См. также == | ||
== Примечания == | == Примечания == |
Версия 22:02, 28 июня 2014
Для данной LL(1)-грамматики оказывается возможным построить нисходящий рекурсивный парсер, который по слову сможет построить его дерево разбора в грамматике или сказать, что слово не принадлежит языку грамматики. Более того, становится возможной даже автоматическая генерация парсеров для таких грамматик[1].
Чтобы написать парсер для LL(1)-грамматики, необходимо построить множества и , после чего по ним можно составить таблицу синтаксического анализатора.
Содержание
Построение FIRST
Для построения
воспользуемся несколькими леммами, которые следуют прямо из определения. Пусть — цепочки из терминалов и нетерминалов, — символ из алфавита.Лемма (1): |
Данная лемма означает, что в множество
правила , где — произвольный терминал или нетерминал, — нужно добавить , если для всех верно, что .Лемма (2): |
Псевдокод
Алгоритм строит для каждого терминала грамматики бесполезных символов. Изначально каждое правило отображается в пустое множество.
function constructFIRST(): forchanged = true while changed changed = true for changed = true if изменился
Утверждение: |
Приведённый алгоритм правильно строит множество для данной грамматики. |
Алгоритм на каждом шаге использует леммы, чтобы построить списки для каждого нетерминала. Поэтому он добавит только те терминалы, которые на самом деле лежат в .
Покажем, что алгоритм найдёт все символы из множества .Предположим, что в грамматике возможен вывод , и алгоритм не включил в . Докажем индукцией по числу шагов , что этого не может быть.Пусть за шагов алгоритм добавит символы в множество для каждого нетерминала , если . База индукции для числа шагов верна, если считать, что для всех терминалов нам известны . Если алгоритм корректно отрабатывает на -ом шаге, то он правильно отработает их на -ом шаге, потому что
Для леммам, следовательно, переход доказан. К тому же алгоритм завершится за конечное число шагов, так как в алгоритм правильно построил по предположению индукции, а для он правильно построит по для каждого нетерминала не может добавиться больше символов, чем есть в алфавите. |
Построение FOLLOW
Сформулируем похожие леммы для построения
.Лемма (1): |