- •3. Опорный конспект лекций
- •3.1. Введение, определение языка
- •3.1.1. Элементы теории языка и их грамматика. Символы, цепочки и операции над ними
- •Формальное определение языка
- •3.1.3. Отношения и операции над ними
- •3.1.4. Требования, предъявляемые к грамматикам
- •Способы представления синтаксиса языка. Задание бесконечного текста конечными средствами. Проблема разбора. Классификация языков
- •3.2. Сканеры (лексические анализаторы)
- •3.2.1. Автоматные грамматики и диаграмма состояний
- •Регулярные выражения и конечные автоматы
- •Недетерминированные конечные автоматы
- •3.3. Грамматики простого предшествования
- •3.3.1. Простые предшествования.
- •Отношения предшествования и их вычисление
- •Операторное предшествование
- •Вычисление отношений операторного предшествования. Алгоритм разбора на основе операторного предшествования
- •3.3.5. Предшествование более высокого порядка
- •3.3.6. Способ представления грамматики в оп
- •3.3.7. Предшествование более высокого порядка
- •3.3.8. Ограниченный контекст
- •Определение 1:1 ограниченного контекстного распознавателя
- •Алгоритм 1:1 ограниченного контекстного преобразователя
- •Примеры разбора цепочек по алгоритму 1:1 ограниченного контекстного преобразователя
- •Определение m: n - ограниченного контекста
- •3.4. Автоматы с магазинной памятью, [ мп-автомат ]
- •Операции над магазином:
- •Операции над состоянием:
- •Операции над входной цепочкой:
- •Автомат задаётся:
- •Варианты мп-автоматов (доопределение)
- •Эквивалентность мп-автоматов и кс-грамматик
- •Мп, работающий снизу вверх
- •Формальное определение для левой свертки
- •Восходящий распознаватель
- •Детерминированный мп-автомат
- •Проблема зацикливания
- •3.4.1. Общие методы синтаксического анализа.
- •Вопросы для самопроверки
- •Нисходящий разбор
- •Нисходящий преобразователь (распознаватель)
- •Моделирование мп –преобразователя. Нисходящий анализ с возвратом Синтез процедуры
- •Нисходящий разбор в терминах грамматик
- •Алгоритм нисходящего разбора
- •Пример:
- •Алгоритм восходящего разбора
- •3.4.2. Польская запись, тетрады, триады, деревья.
- •Перевод индексной записи в тетрады
- •3.5. Теория перевода
- •3.5.1. Формализмы определения перевода
- •3.5.2. Синтаксически управляемый перевод
- •3.5.3. Конечные преобразователи. (Простейший транслятор)
- •3.5.4. Преобразователи с магазинной памятью
- •Лабораторная работа №7 Поиск основы в грамматиках простого предшествования
- •5. Контроль знаний
- •Глоссарий
Алгоритм нисходящего разбора
Леворекурсивные грамматики неприменимы для нисходящего разбора.
Используются 2 стека (магазина), счетчик, в котором хранится текущая позиция указателя.
Пусть задана не леворекурсивная грамматика G{N, S, P, Z}. Правила из Р занумерованы для каждого нетерминала А Î N. Упорядочим его альтернативы:
А = a1 | a2 | a3.
A1 = a1.
A2 = a2.
A3 = a3.
Конфигурацию алгоритма будем характеризовать четверкой: (S, i, L1, L2), где S – состояние алгоритма.
i – счетчик положения входного указателя.
L1 – стек, содержащий историю используемых альтернатив и терминальных символов, которые прошли удачное сравнение.
L2 – вершина слева хранит левовыводимую цепочку, ту ее часть, которая получилась к данному моменту в результате развертки нетерминала.
(q, i, $a, Ab) |¾ (q, i, $a, aib). Если существует Ai = ai (А имеет i альтернатив).
(q, i, $g, aaib) |¾ (q, i+1, $gAia, aib). Если Ai = аai и произошло сравнение, то а (терминал входной цепочки) = а (терминал в растущем дереве).
Примечание: i и индекс у ai – это две разные вещи!
(q, n+1, $p, e) |¾ (t, n+1, $, e);
h(Ai) = i h(p) – номера используемых правил;
h(a) = e.
неудачное сравнение: (q, i, $gAia, b) |¾ (q, i, $gAia, b) |¾
теперь возврат по дереву |¾ (q, i-1, $g, Aiab).
Пример:
E1:= T+E.
E2:= T.
T1:= F*T.
T2:= F.
F1:= (E).
F2:= a.
(q, 1, $, E1) |¾ (q, 1, $E1, T+E) |¾ (q, 1, $E1T1,F*T+E) |¾ (q, 1, $E1T1F2,a*T+E) |¾
(q, 2, $E1T1F2a,*T+E) |¾ (b, 2, $E1T1F2a,*T+E) |¾ (b, 1, $E1T1,F*T+E) |¾
(q, 1, $E1T2,F+E)|¾ (q, 1, $E1T2F2,a+E)|¾ (q, 3, $E1T2a+, E) |¾ (q, 3, $E1T2a+E1, T+E) |¾
(q, 3, $E1T2a+E1T1,F*T+E).
а+а#
E:=E+T|T
|→ |→ |→
|→ |→ - a здесь нужна для возможности вернуться, в случае неудачи мы загружаем в стек терминальный символ |→ - неудачное сравнение, возврат по дереву
|→ |→ |→ |→
|→ |→ |→ - удачное сравнение, перемещаем указатель: ;
|→ |→ |→ далее мы повторим то же самое, но указатель уже передвинется, сравнение будет удачно, но дерево останется, , и мы вернёмся назад и возьмём вторую альтернативу |→ |→ |→ - пояснения по поводу последней Т2 в последних скобках: машина выбрала первую альтернативу и, столкнувшись с неудачей вернулась и выбрала бы
Т2|→ |→
сравниваем удачно
Гомоморфизм .
Восходящий разбор
Должно быть понятно, что каким бы методом («сверху вниз» или «снизу вверх») мы ни воспользовались для синтаксического разбора строки , где G — контекстно свободная грамматика, результат должен быть один (это утверждение справедливо при условии допустимости использования обоих методов), так как эти методы отличаются лишь способами построения деревьев.
Если метод синтаксического разбора «сверху вниз» рекомендует построение указанных деревьев начиная с корня, то метод «снизу вверх» рекомендует строить их наоборот, начиная с листьев и кончая корнем дерева. Введенные входные строки в последнем случае анализируются слева направо; получаемые в процессе подстроки сравниваются с правыми частями продукции грамматики, а при совпадении заменяются или приводятся к нетерминальному символу, стоящему в левой части таких продукций. В результате такой замены может быть получена сентенциальная форма грамматики, а затем вся процедура повторяется до тех пор, пока полученная сентенциальная форма не примет вид S, где символом S помечен корень дерева вывода. В результате будет получена последовательность схем вывода и соответствующих им приведений, позволяющая построить дерево вывода от листьев до корня. Каждому элементу этой последовательности, очевидно, соответствует один родительский узел дерева вывода.
Рассмотрим грамматику G1, имеющую следующие продукции:
G1 - однозначная грамматика, и, следовательно, любой строке соответствует единственное дерево вывода.
Например, дерево вывода для строки приведено на рис. 2, д.
а) б) в)
г) д)
Рис. 2. Дерево вывода для строки
Далее каждому дереву вывода соответствует единственная правосторонняя схема вывода, т. е. такая схема вывода, в которой всегда выводится самый правый нетерминальный символ. Так, дереву вывода, рассмотренному в вышеприведенном примере, соответствует правосторонняя схема вывода:
.
Рассматриваемый метод синтаксического разбора «снизу вверх», позволит построить такую схему вывода справа налево. Пример построения дерева вывода для строки bbaa$ показан на рис.1. Подстроку, которая приводится, называют основой правосторонней сентенциальной формы, или правосторонней простой фразой. Процесс построения дерева вывода для нашего примера иллюстрируется табл.1.
Таблица1
Правосторонняя сентенциальная форма |
Основа |
Замещающий символ |
bbaa$ |
а (левый символ) |
А |
bbАа$ |
а |
А |
bbАА$ |
bАА |
А |
bА$ |
bА |
С |
С$ |
С$ |
S |
Итак, восходящий разбор связан с отображением входной цепочки в последовательность обращенных правых выводов.
Пусть G(N, S, P, S) – грамматика, правила которой занумерованы 1, 2 … р.
Пусть a - некоторая цепочка в этой грамматике, где a Î (NÈS*).
Тогда правый разбор цепочки a - обращенная последовательность правил, примененных при правом выводе.
E:= E+T;
E:=T;
T:=T*F;
T:=F;
F:=(E);
F:=i.
2 3 5 1 4 6 2
E => T => T*F => T*(E) => T*(E+T) => T*(E+F) => T*(E+i) => T*(T+i) =>
4 6 4 6
=> T*(F+i) => T*(i+i) => F*(i+i) => i*(i+i).
Правый разбор: 6 4 6 4 2 6 4 1 5 3 2.
Набираем в магазине цепочку терминальных символов и смотрим, есть ли в правых частях правил соответствующие нетерминальные символы: МП={Q, S, Г, D, d, q0, Z, F};
d : Q*S*Г -> Q1*Г**D* - функция отображения, где * - означает цепочки.
Будем рассматривать Z как маркер дна магазина,
S {i, (, ), *, +},
D (1…6) 1,2…6 – номера правил,
Г {N È S}.
Рассмотрим несколько примеров функции отображения:
d(q, a, Z) = (q, Za, e),
d(q, e, Za) = (q, A, i),
d(q, e, ZE) = (r, e, e).
A:= a, q Î Q, r Î F;
Е – начальный символ грамматики,
a – то же самое, что и i (терминал),
b – любой терминальный символ из грамматики.
d (q, e, ZE+T) = (q, E, 1);
d (q, e, ZT) = (q, E, 2);
d (q, e, ZT*F) = (q, T, 3);
d (q, e, ZF) = (q, T, 4);
d (q, e, Z(E)) = (q, F, 5);
d (q, e, Za) = (q, F, 6);
d (q, b, Z) = (q, Zb, e);
d (q, e, ZE) = (q, e, e).
Рассмотрим цепочку a*(a + a):
(q, a*(a + a), Z, e) |¾ (q, *(a + a), Za, e) |¾ (q, *(a + a), ZF, 6) |¾ (q, *(a + a), ZT, 64).
|¾ (q, (a + a), ZT*, 64) |¾ (q, a + a), ZT*(, 64) |¾ (q, + a), ZT*(a, 64).
|¾ (q, + a), ZT*(F, 646) |¾ (q, + a), ZT*(T, 6464) |¾ (q, + a), ZT*(E, 64642).
|¾ (q, a), ZT*(E+, 64642) |¾ (q, ), ZT*(E+a, 64642) |¾ (q, ), ZT*(E+T, 6464264).
|¾ (q, ), ZT*(E, 64642641) |¾ (q, e, ZT*(E), 64642641) |¾ (q, e, ZT*F, 646426415).
|¾ (q, e, ZT, 6464264153) |¾ (q, e, ZE, 64642641532).
Работа преобразователя в данном примере:
на такте 1 преобразователь переносит входной символ в магазин. Всякий раз, когда наверху магазина появится основа, преобразователь может свернуть ее по правилу 2 и выдать при этом номер используемого правила. Это происходит до тех пор, пока верхним символом в магазине не станет начальный символ (Е), за которым следует маркер дна (Z). Это означает, что входная цепочка прочитана, и по правилу 3 попадаем в заключительное состояние.