Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ШПОРЫ

.docx
Скачиваний:
14
Добавлен:
10.06.2015
Размер:
258.56 Кб
Скачать

50 Рекурсивный спуск

В основе стратегии нисходящего анализа лежит левосторонний разбор строки языка. Исходной сентенциальной формой является начальный символ грамматики, а целевой – заданная строка языка. На каждом шаге разбора правило грамматики применяется к самому левому нетерминалу сентенции.

И здесь может возникать основная проблема нисходящего анализа – неоднозначность выбора правила грамматики. Эффективным решением проблемы является привлечение группы очередных символов входной строки.

Данный процесс соответствует построению дерева разбора цепочки сверху вниз (от корня к листьям).

Пример Дана грамматика с правилами

Требуется выполнить анализ строки cabca^.

Левосторонний вывод цепочки имеет вид:

Достаточные условия применимости метода рекурсивного спуска

Данные требования являются достаточными, но не являются необходимыми. Можно применить эквивалентные преобразования КС-грамматик, которые способствуют приведению грамматики к требуемому виду, но не гарантируют его достижения.

52 Распознаватели LL(k)-грамматик

Определение КС-грамматика обладает свойством LL(k) для некоторого k>0, если на каждом шаге вывода для однозначного выбора очередной альтернативы МП-автомату достаточно знать символ на верхушке стека и рассмотреть первые k символов от текущего положения считывающей головки во входной строке.

Определение КС-грамматика называется LL(k)-грамматикой, если она обладает свойством LL(k) для некоторого k>0.

В основе распознавателя LL(k)-грамматик лежит левосторонний разбор строки языка. Исходной сентенциальной формой является начальный символ грамматики, а целевой – заданная строка языка. На каждом шаге разбора правило грамматики применяется к самому левому нетерминалу сентенции. Данный процесс соответствует построению дерева разбора цепочки сверху вниз (от корня к листьям).

Аббревиатура LL(k): первая «L» (от слова «left») означает левосторонний ввод исходной цепочки символов, вторая «L» - левосторонний вывод в процессе работы распознавателя.

Определение Для построения распознавателей для LL(k)-грамматик используются два множества:

53

54 Алгоритм построения множества FIRST(1, A) использует грамматику G¢.

Шаг 1. Первоначально внести во множество первых символов для каждого нетерминального символа А все символы, стоящие в начале правых частей правил для этого нетерминала, т.е.

" АÎVN FIRST0 (1, A) = {X | A®Xa ÎP, XÎ(VТÈVN), (VТÈVN)*}.

Шаг 2. Для всех АÎVNположить:

FIRST i+1(1, A) = FIRST i(1, A) È FIRSTi (1, B), " ВÎ(FIRST(1, A)ÇVN).

Шаг 3. Если существует АÎVN, такой что FIRSTi+1(1, A) ¹ FIRSTi (1, A), то присвоить i=i+1 и вернуться к шагу 2, иначе перейти к шагу 4.

Шаг 4. Исключить из построенных множеств все нетерминальные символы, т.е.

" AÎVN FIRST(1, A) = FIRSTi (1, A) /N.

55 Построение множества FOLLOW(1, A)

Алгоритм основан на использовании правил вывода грамматики G.

Шаг 1. Первоначально внести во множество последующих символов для каждого нетерминального символа А все символы, которые в правых частях правил вывода встречаются непосредственно за символом А, т.е.

" AÎVN FOLLOW 0 (1, A) = {X | $ B ® aAXb Î P, B Î VN, X Î (VTÈVN),

a, bÎ(VTÈVN)*}.

Шаг 2. Внести пустую строку во множество FOLLOW(1, S), т.е.

FOLLOW(1, S) = FOLLOW(1, S)È{e}.

Шаг 3. Для всех АÎVN вычислить:

FOLLOW ¢i(1,A)=FOLLOWi(1,A)ÈFIRST(1,B),"BÎ(FOLLOWi(1,A)ÇVN).

Шаг 4. Для всех АÎVN положить:

FOLLOW² i(1, A)=FOLLOW¢ i(1, A)ÈFOLLOW¢i(1, B),

"BÎ(FOLLOW¢i(1, A)ÇVN), если $ правило B®e.

Шаг 5. Для всех АÎVN определить:

FOLLOW i(1, A) = FOLLOW²i(1, A)ÈFOLLOW² i(1, B),

для всех нетерминальных символов BÎVN, имеющих правило вида

B®aA, aÎ(VTÈVN)*.

Шаг 6. Если существует AÎVN такой, что FOLLOWi+1(1,A)¹FOLLOWi(1,A), то положить i:=i+1 и вернуться к шагу 3, иначе перейти к шагу 7.

Шаг 7. Исключить из построенных множеств все нетерминальные символы, т.е. " AÎVN FOLLOW(1, A) = FOLLOW i(1, A) \ N.

56 Алгоритм «сдвиг-свертка» для LL(1)-грамматик

Шаг 1. Помещаем в стек начальный символ грамматики S, а во входной буфер исходную цепочку символов.

Шаг 2. До тех пор пока в стеке и во входном буфере останется только пустая строка e либо будет обнаружена ошибка в алгоритме разбора, выполняем одно из следующих действий:

- если на верхушке стека находится нетерминальный символ А и очередной символ входной строки символ а, то выполняем операцию «свертка» по правилу А®х при условии, что аÎFIRST(1, x), т.е. извлекаем из стека символ А и заносим в стек строку х, не меняя содержимого входного буфера;

- если на верхушке стека находится нетерминальный символ А и очередной символ входной строки символ а, то выполняем операцию «свертка» по правилу А®e при условии, что аÎFOLLOW(1, A), т.е. извлекаем из стека символ А и заносим в стек строку e, не меняя содержимого входного буфера;

- если на верхушке стека находится терминальный символ а, совпадающий с очередным символом входной строки, то выполняем операцию «выброс», т.е. удаляем из стека и входного буфера данный терминальный символ;

- если содержимое стека и входного буфера пусто, то исходная строка прочитана полностью, и разбор завершен удачно;

- если ни одно из данных условий не выполнено, то цепочка не принадлежит заданному языку, и алгоритм завершает свою работу с ошибкой

57 Работу распознавателя с подбором альтернатив можно неформально описать следующим образом: если на верхушке стека МП-автомата находится нетерминальный символ A, то его можно заменить на цепочку символов ? при условии, что в грамматике языка есть правило A ? ?, не сдвигая при этом считывающую головку автомата (этот шаг работы называется «подбор альтернативы»); если же на верхушке стека находится терминальный символ a, который совпадает с текущим символом входной цепочки, то этот символ можно выбросить из стека и передвинуть считывающую головку на одну позицию вправо (этот шаг работы называется «выброс»). Данный МП-автомат может быть недетерминированным, поскольку при подборе альтернативы в грамматике языка может оказаться более одного правила вида A ->?, тогда функция ?(q,?,A) будет содержать более одного следующего состояния — у МП-автомата будет несколько альтернатив. Распознаватель с подбором альтернатив является нисходящим распознавателем: он читает входную цепочку символов слева направо и строит левосторонний вывод. Название «нисходящий» дано ему потому, что дерево вывода в этом случае следует строить сверху вниз, от корня к концевым вершинам («листьям»)1. Работу распознавателя на основе алгоритма «сдвиг-свертка» можно описать так: если на верхушке стека МП-автомата находится цепочка символов ?, то ее можно заменить на нетерминальный символ A при условии, что в грамматике языка существует правило вида A ? ?, не сдвигая при этом считывающую головку автомата (этот шаг работы называется «свертка»); с другой стороны, если считывающая головка автомата обозревает некоторый символ входной цепочки a, то его можно поместить в стек, сдвинув при этом головку на одну позицию вправо (этот шаг работы называется «сдвиг» или «перенос»).

58 Отношения =, <, > называют отношениями простого предшествования для символов грамматики

грамматики предшествования исходит из того, что для каждой упорядоченной пары символов в грамматике устанавливается отношение, называемое отношением предшествования. В процессе разбора МП-автомат сравнивает текущий символ входной цепочки с одним из символов, находящихся на верхушке стека автомата. В процессе сравнения проверяется, какое из возможных отношений предшествования существует между этими двумя символами. В зависимости от найденного отношения выполняется либо сдвиг, либо свертка. При отсутствии отношения предшествования между символами алгоритм сигнализирует об ошибке.

Метод предшествования основан на том факте, что отношения между двумя соседними символами распознаваемой строки соответствуют трем следующим вариантам:

Bi = Bi+1, если символы Bi и Bi+1 принадлежат основе;

Bi < Bi+1, если Bi+1 – крайний левый символ некоторой основы;

Bi > Bi+1, если Bi – крайний правый символ некоторой основы.

59 Если грамматика является грамматикой простого предшествования, то для поиска основы каждой ее сентенции надо просматривать элементы сентенции слева направо и найти самую левую пару символов xj и xj+1, такую что xj>xj+1. Окончанием основы сентенции будет xj. Далее просматривать элементы сентенции справа налево, начиная с символа xj до тех пор, пока не будет найдена самая правая пара символов xi-1 и xi, такая что xi-1 < xi. Заголовком основы будет символ xi. Таким образом, будет найдена основа сентенции, имеющая вид xi xi+1xj-1 xj.

60 Шаг 1. Для каждого нетерминального символа А ищем все правила, содержание А в левой части. Во множество L(A) включаем самый левый символ из правой части правил, а во множество R(A) – самый крайний правый символ из правой части, т.е.

A VN: L0(A) = {X | AXy, X V, y V*},

R0(A) = {X | AyX, X V, y V*}.

Шаг 2. Для каждого нетерминального символа А: если множество L(A) содержит нетерминальные символы грамматики А, A, …, то множество L(A) надо дополнить символами, входящими в соответствующие множества L(А), L(A) и т.д., … и не входящими в L(A). Аналогичную операцию выполнить для множеств R(A), т.е.

A VN: Li(A) = Li-1(A)Li-1(B), B  (Li-1(A) VN),

Ri(A) = Ri-1(A)Ri-1(B),  B  (Ri-1(A) VN).

Шаг 3. Если на предыдущем шаге хотя бы одно множество L(A) или R(A) для некоторого символа грамматики изменилось, то вернуться к шагу 2, иначе построение закончено. Т.е. если существует AVN: Ri(A)Ri-1(A) или Li(A)Li-1(A), то положить i:=i+1 и вернуться к шагу 2, иначе построение закончено и R(A) = Ri(A) и L(A) = Li(A).

61 Построение матрицы предшествования основано на двух вспомогательных множествах, определяемых следующим образом:

L(A) = {X | A*Xz}, AVN, XV, zV* - множество крайних левых символов относительно нетерминального символа А;

R(A) = {X |A*zX}, AVN, XV, zV* - множество крайних правых символов относительно нетерминального символа А.

62 Шаг 1. Поместить в верхушку стека символ н, считывающую головку – в начало входной цепочки символов.

Шаг 2. До тех пор, пока не будет обнаружена ошибка, либо успешно завершен алгоритм разбора, сравниваем отношение простого предшествования символа на верхушке стека и очередного символа входной строки. При этом возможны следующие ситуации:

если самый верхний символ стека имеет меньшее или равное предшествование, чем очередной символ входной строки, то производим операцию «сдвиг» (перенос текущего символа из входной цепочки в стек и перемещение считывающей головки на один символ вправо);

если самый верхний символ стека имеет большее предшествование, чем очередной символ входной строки, то выполняем операцию «свертка». Для этого находим на верхушке стека «основу» сентенции, т.е. все символы, имеющие равное предшествование или один символ на верхушке стека

63 Определение грамматики операторного предшествования

Определение. КС-грамматика G (VN, VT, P, S) называется грамматикой операторного предшествования, если выполняются следующие условия:

1)Для каждой упорядоченной пары терминальных символов выполняется не более чем одно из трех отношений предшествования:

а) а =× b, если и только если существует правило A—>xaby ÎР или

правило А->хаСbу, где a,bÎVT, A,C ÎVN, x,yÎV*;

б) а <× b, если и только если существует правило А->хаСу ÎР и вывод C=>*bz или вывод C=>*Dbz, где a,bÎVT, A,C,DÎVN, x,y,zÎV*;

в) а ×> b, если и только если существует правило А—>хСbу ÎР и вывод C=>*za или вывод C=>*zaD, где a,bÎVT, A,C,DÎVN, x,y,zÎV*.

2) Различные правила в грамматике имеют разные правые части, e-правила отсутствуют.

3) Правила грамматики операторного предшествования не могут содержать двух смежных нетерминальных символов в правой части, т.е. в грамматике операторного предшествования G(VN,VT,P,S) не может быть ни одного правила вида: А->хВСу, где A,B,CÎVN, x,yÎV* (здесь х и у — это произвольные цепочки символов, могут быть и пустыми).

64Определение грамматики операторного предшествования

Определение. КС-грамматика G (VN, VT, P, S) называется грамматикой операторного предшествования, если выполняются следующие условия:

1)Для каждой упорядоченной пары терминальных символов выполняется не более чем одно из трех отношений предшествования:

а) а =× b, если и только если существует правило A—>xaby ÎР или

правило А->хаСbу, где a,bÎVT, A,C ÎVN, x,yÎV*;

б) а <× b, если и только если существует правило А->хаСу ÎР и вывод C=>*bz или вывод C=>*Dbz, где a,bÎVT, A,C,DÎVN, x,y,zÎV*;

в) а ×> b, если и только если существует правило А—>хСbу ÎР и вывод C=>*za или вывод C=>*zaD, где a,bÎVT, A,C,DÎVN, x,y,zÎV*.

2) Различные правила в грамматике имеют разные правые части, e-правила отсутствуют.

3) Правила грамматики операторного предшествования не могут содержать двух смежных нетерминальных символов в правой части, т.е. в грамматике операторного предшествования G(VN,VT,P,S) не может быть ни одного правила вида: А->хВСу, где A,B,CÎVN, x,yÎV* (здесь х и у — это произвольные цепочки символов, могут быть и пустыми).

65

66 Матрица предшествования служит основой для работы распознавателя языка, заданного грамматикой операторного предшествования. Поскольку она содержит только терминальные символы, то будет иметь меньший размер, чем аналогичная матрица для грамматики простого предшествования. Следует отметить, что напрямую сравнивать матрицы двух грамматик нельзя — не всякая грамматика простого предшествования является грамматикой операторного предшествования, и наоборот.

67 Алгоритм состоит из следующих шагов.

Шаг 1. Поместить в верхушку стека символ , считывающую головку — в начало входной цепочки символов.

Шаг 2. Сравнить с помощью отношения предшествования терминальный символ, ближайший к вершине стека (левый символ отношения), с текущим символом входной цепочки, обозреваемым считывающей головкой (правый символ отношения). При этом из стека надо выбрать самый верхний терминальный символ, игнорируя все возможные нетерминальные символы.

Шаг 3. Если имеет место отношение или =×, то произвести сдвиг (перенос тощего символа из входной цепочки в стек и сдвиг считывающей головки на один шаг вправо) и вернуться к шагу 2. Иначе перейти к шагу 4.

Шаг 4. Если имеет место отношение ·>, то произвести свертку. Для этого надо найти на вершине стека все терминальные символы, связанные отношением («основа»), а также все соседствующие с ними нетерминальные символы (при определении отношения нетерминальные символы игнорируются).

Если терминальных символов, связанных отношением =×, на верхушке стека нет, то в качестве основы используется один, самый верхний в стеке терминальный символ стека.

Если правило, совпадающее с основой, найти не удалось, то необходимо прервать выполнение алгоритма и сообщить об ошибке, иначе, если разбор не закончен, то вернуться к шагу 2

Шаг 5. Если не установлено ни одно отношение предшествования между текущим символом входной цепочки и самым верхним терминальным символом в стеке, то надо прервать выполнение алгоритма и сообщить об ошибке.

68 Распознаватели LR(k)-грамматик основаны на построении дерева разбора снизу вверх и правостороннем выводе цепочек

69 Соотношение классов КС-грамматик

В общем случае можно выделить правоанализируемые и левоанализируемые КС-грамматики. Первые предполагают построение левостороннего (восходящего) распознавателя, вторые — правостороннего (нисходящего). Это не значит, что для КС-языка, заданного, например, некоторой левоанализируемой грамматикой, невозможно построить расширенный МП-автомат, который порождает правосторонний вывод. Указанное разделение грамматик относится только к построению на их основе детерминированных МП-автоматов и детерминированных расширенных МП-автоматов. Только эти типы автоматов представляют интерес при создании компиляторов и анализе входных цепочек языков программирования. Недетерминированные автоматы, порождающие как левосторонние, так и правосторонние выводы, можно построить в любом случае для языка, заданного любой КС-грамматикой, но для создания компилятора такие автоматы интереса не представляют.

Соотношение классов левоанализируемых и правоанализируемых КС-грамматик

70Транслятор – это программа, которая переводит входную программу на исходном (входном) языке в эквивалентную ей входную программу на результирующем языке (выходном) языке. В работе транслятора участвует три программы. Транслятор это часть ПО, обычно это символьный файл, который содержит текст программы удовлетворяющий синтаксис и семантику входного языка. Итак чтобы создать транслятор, необходимо прежде всего выбрать входной и выходной языки транслятор является как бы переводчиком. Например, если перевести с языка С в ассемблер, по сути ни чем не отличается от перевода с русского на английский. С английского (translator) означает переводчик. Результатом работы транслятора буте программа, но только в том случае, если текст исходной программы является правильным – не содержит ошибок с точки зрения синтаксиса и семантики входного языка.

71.Лексика, синтаксис и семантика языка

Лексика-это совокупность слов(словарный запас) языка. Слово или лексическая единица (лексема) языка-это конструкция, которая состоит из элементов языка и не содержит в себе других конструкций. В языках программирования лексемами являются ключевые слова, идентификаторы, константы, метки, знаки операций; в них так же существуют разделители (запятые, скобки, точки с запятой и т.д.)

Синтаксис языка - это набор правил, определяющий допустимые конструкции языка. Синтаксис определяет «форму языка»-задает набор цепочек символов, которые принадлежат языку.Пример, любой окончивший среднюю школу может сказать, что строка «3+2» является арифметическим выражением, а «3 2+»-не является. Правда не каждый задумается что он оперирует синтаксисом алгебры.

Семантика языка - это раздел языка, определяющий значение предложений языка. Семантика определяет «содержание языка»- задает значение для всех допустимых цепочек языка. Пример семантики из алгебры «3+2» есть сумма чисел 3 и 2 , а так же то, что «3+2=5»-это истинное выражение. Однако любому ученику изложить синтаксис алгебры проще, чем семантику

72 Транслятор – это программа, которая переводит входную программу на исходном (входном) языке в эквивалентную ей входную программу на результирующем языке (выходном) языке. В работе транслятора участвует три программы.

Компилятор - это транслятор, который осуществляет перевод исходной программы в эквивалентную ей объектную программу на языке машинных команд или на языке машинных команд. Компилятор – это составитель! (компоновщик)

Интерпретатор – это программа, которая воспринимает входную программу на исходном языке и выполняет ее. Интерпретатор в отличии транслятора не порождает результирующую программу (и вообще кого либо кода)

Ассемблер – это язык низкого уровня. Структура и взаимосвязь цепочек этого языка близки к машинным командам целевой вычислительной системы, где должна выполняться результирующая программа (ресурсы этого языка позволяют разработчику управлять ресурсами машины Опрер памятью, процем, внешними устройствами и т.д.)

73

См вопрос 71

Компилятор – это транслятор, осуществляющий перевод исходной программы в эквивалентную ей объектную программу на языке ассемблера. Отличие компилятора от транслятора состоит в том, его входная (результирующая) программа должна быть написана на языке машинных команд или на ассемблере. Результат работы транслятора может быть написан на любом языке. На этапе анализа распознается текст исходной программы, создаются и заполняются таблицы идентификаторов. Результатом анализа является некое внутреннее представление программы, понятное компилятору. На этапе синтеза из внутреннего представления программы и информации из таблицы идентификаторов, получается результирующая объектная программа.

74 Лексический анализ. Эту часть компилятора выполняет сканер, который читает литеры программы (символы) на исходном языке и строит из них слова (лексемы) исходного языка. На входе сканера (лексического анализатора) текст исходной программы, выходная информация передается для дальнейшей обработки на этап синтаксического разбора.

Задачи – упрощать работу с текстом исходной программы на этапе синтаксического разбора и сокращать объем обрабатываемой информации, а так же упрощает алгоритм разбора лексем. В основном лексические анализаторы выполняют исключение из текста программы комментариев, незначащих пробелов символов табуляции и перевода строки, а также выделение лексем следующих типов: идентификаторов, строковых, символьных и числовых констант, знаков операций и разделителей.

75 Анализ текста проводится путем разбора по регулярным грамматикам и опирается на способ разбора по диаграмме состояний, снабженной дополнительными пометками-действиями. В диаграмме состояний с действиями каждая дуга имеет вид, представленный на рисунке 2.4. Смысл этой конструкции: если текущим является состояние А и очередной входной символ совпадает с для какого либо i, то осуществляется переход в новое состояние В, при этом выполняются действия D1, D2, …, Dm. Для удобства разбора вводится дополнительное состояние диаграммы ER, попадание в которое соответствует появлению ошибки в алгоритме разбора. Переход по дуге, не помеченной ни одним символом, осуществляется по любому другому символу, кроме тех, которыми помечены все другие дуги, выходящие из данного состояния.

Рисунок– Дуга ДС с действиями Алгоритм Разбор цепочек символов по ДС с действиями

Шаг 1. Объявляем текущим начальное состояние ДС H.

Шаг 2. До тех пор, пока не будет достигнуто состояние ER или конечное состояние ДС, считываем очередной символ анализируемой строки и переходим из текущего состояния ДС в другое по дуге, помеченной этим символом, выполняя при этом соответствующие действия. Состояние, в которое попадаем, становится текущим.

ЛА строится в два этапа:

1) построить ДС с действиями для распознавания и формирования внутреннего представления лексем;

2) по ДС с действиями написать программу сканирования текста исходной программы. Сканер это и есть лексический анализатор! См вопрос 74

76