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

Создание распределенной системы решения задач

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

2.9. Разработка лексического анализатора входного языка

Анализ постановки задачи на входном языке включает

¾лексический,

¾синтаксический,

¾семантический анализ.

На этапе лексического анализа распознаются и выделяются в исходном тексте все лексемы. В рассматриваемом примере лексемами являются:

¾Тип 1: идентификаторы компонентов постановки задачи – в данном случае это фактически ключевые слова: "n", "A", "x0", "t0", "tk", "h".

¾Тип 2: разделитель: точка с запятой ";".

¾Тип 3: вещественные десятичные константы со знаком - произвольная последовательность цифр (от "0" до "9"), начинающаяся с любой цифры или знаков "+" или "-", в составе которой может присутствовать десятичная точка "." или запятая ",".

¾Тип 4: целые десятичные константы без знака – произвольная последовательность цифр (от "0" до "9"), начинающаяся с любой цифры.

¾Тип 5: знак операции присваивания "=".

¾Тип 6: открывающаяся квадратная скобка "[".

¾Тип 7: закрывающаяся квадратная скобка "]".

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

2.9.1.Построение конечного автомата лексического анализатора

Конечный автомат может быть задан с помощью пяти параметров:

M (Q,Σ,δ,q0, F ) ,

где Q – конечное множество состояний автомата;

Σ – конечное множество допустимых входных символов (входной алфавит);

δ – заданное отображение множества Q×Σ во множество подмножеств P(Q), т.е. δ: Q×Σ → P(Q) – функция переходов автомата;

q0 Q – начальное состояние автомата;

F Q – множество заключительных состояний автомата.

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

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

Методические указания к выполнению курсовой работы

21

 

Системное программное обеспечение

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

изображают переходы из одного состояния в другое, а символы пометки (нагрузки) дуг соответствуют функции перехода конечного автомата. Если функция перехода конечного автомата предусматривает переход из состояния q в q' по нескольким символам, то между ними строится одна дуга, которая помечается всеми символами, по которым происходит переход из состояния q в q'.

Границами лексем для данного распознавателя служат " " – пробел, знаки перевода строки "\n" и возврата каретки "\r", "," – запятая, ";" – точка

сзапятой, открывающаяся и закрывающаяся квадратные скобки "[", "]", знак равенства "=", которые, в свою очередь также являются лексемами (кроме пробела, знаков перевода строки и возврата каретки).

Всвязи с этим границы лексем являются эффективно распознаваемыми, а, следовательно, нет необходимости во взаимодействии

ссинтаксическим анализатором.

Построим конечный автомат, эквивалентный грамматике G1. Шаг 1.

Строим множество состояний автомата. Начальное состояние автомата – Н=<задача>.

Q = VN {H}= {<задача> | <размерность> | <значение размерности> | <матрица А> | <элементы матрицы А> | <все элементы матрицы А> | <элемент матрицы А> | <дробь элемента матрицы А> | <x0> | <все элементы x0> | <элемент x0> | <дробь элемента x0> | <t0> | <значение t0> | <дробь значения t0> | <tk> | <значение tk> | <дробь значения tk> | <h> | <значение h> | <дробь значения h> | <остаток задачи1> |<остаток задачи2> | <остаток задачи3> | <остаток задачи4> | <остаток задачи5> | <остаток задачи6> | <остаток задачи7> | <остаток задачи8> | <остаток задачи9> | <остаток задачи10> | <остаток задачи11> | <остаток задачи12> | <остаток задачи13> | <остаток задачи14> | <Успех>}.

Шаг 2.

В качестве алфавита входных символов принимаем множество терминальных символов грамматики.

Σ = {"A"|"x"|"t"|"0"|"k"|"h"|"E"|"0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"|"."|"+"|"- "|"["|"]"|";"|","|" "}.

Шаг 3.

Рассматриваем множество правил грамматики и строим функцию переходов автомата.

Для начального правила <задача>::=n<размерность>

δ(Н,"n")={<размерность>}.

Для правила <размерность>::= =<значение размерности>

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

22

М.Ф.Степанов

Создание распределенной системы решения задач

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

δ(<размерность>,"=")={<значение размерности>}. Для правил

<значение размерности>::=0<значение размерности> | 1<значение размерности> | 2<значение размерности> | 3<значение размерности> | 4<значение размерности> | 5<значение размерности> | 6<значение размерности> | 7<значение размерности> | 8<значение размерности> | 9<значение размерности> | ;<остаток задачи1>

δ(<значение размерности>,"0")={<значение размерности>}. δ(<значение размерности>,"1")={<значение размерности>}. δ(<значение размерности>,"2")={<значение размерности>}. δ(<значение размерности>,"3")={<значение размерности>}. δ(<значение размерности>,"4")={<значение размерности>}. δ(<значение размерности>,"5")={<значение размерности>}. δ(<значение размерности>,"6")={<значение размерности>}. δ(<значение размерности>,"7")={<значение размерности>}. δ(<значение размерности>,"8")={<значение размерности>}. δ(<значение размерности>,"9")={<значение размерности>}. δ(<значение размерности>,";")={<остаток задачи1>}.

И так далее для всех правил грамматики.

Построенный конечный автомат, очевидно, является детерминированным. Поэтому его преобразование не требуется.

На основании этого конечного автомата несложно построить программную реализацию лексического анализатора.

2.9.2.Формирование текстового представления постановки задачи

Вначале модифицируем тестовое приложение TaskSolve, использующее функциональный программный модуль, введя формирование текстового представления постановки задачи на основе визуального представления, заданного пользователем на экранной форме. Для этого на экранную форму добавим страницу «Постановка задачи» и разместим на ней Memo-поле, назвав его, например, TaskTextMemo, в которое и будем записывать текстовое представление постановки задачи.

Разработаем функцию setTextTask(), осуществляющую формирование текстового представления постановки задачи на основании данных, заданных пользователем в полях экранной формы. Исходный программный код функции приведен на листинге 27. Модифицированный исходный программный код функции обработки щелчка на кнопке «Решение задачи», использующий функцию setTextTask() и отображение результатов ее работы на экранной форме с помощью функции

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

Методические указания к выполнению курсовой работы

23

 

Системное программное обеспечение

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

viewTextTask(), приведен на листинге 28. Изменения отмечены красным цветом.

2.9.3.Программная реализация лексического анализатора входного языка

Предварительно создадим на экранной форме тестового приложения элементы для визуализации результатов работы лексического анализатора. Поэтому вначале определим сведения, которые должны сохраняться для каждой лексемы. К традиционным относятся:

1)текст лексемы;

2)тип лексемы;

3)значение лексемы для целочисленных лексем типа "константа";

4)значение лексемы для вещественных лексем типа "константа";

5)номер строки, где встретилась лексема;

6)позиция лексемы в строке;

7)позиция лексемы относительно начала исходного текста.

Для хранения сведений о лексеме разработаем структуру данных. Оформим ее в виде класса TLexem языка С++, снабдив необходимой функциональностью. Исходный код класса TLexem приведен на листингах

29 - 30.

Пусть заданием предусмотрено использование массива записей для организации таблиц анализатора.

На листингах 31 - 32 приведен исходный код класса TLexemList для работы с массивом лексем.

Поскольку идентификаторы являются разновидностью лексем, то построим класс идентификаторов TIdent на основе класса лексем (листинги 33 - 34), а также и список идентификаторов TIdentList (листинги

35 - 36) на основе TLexemList.

На листинге 37 приведен фрагмент основной программы лексического анализатора. На листинге 38 приведен программный код функций, эмулирующих работу конечного автомата лексического анализатора в состояниях <задача>, <размерность>, <значение размерности>, <остаток задачи1>.

Транслятор также будем запускать в специальном потоке команд, для которого создадим класс TTranslationThread (см. листинги 39, 40).

Для управления потоком на экранной форме приложения также используем кнопки "Старт", "Стоп", "Продолжить", "Прекратить", исходные коды функций которых приведены на листингах 41 - 44 соответственно. Исходный код функции, вызываемой по окончании работы потока команд (нити) транслятора приведен на листинге 45.

На рисунках 13 - 15 приведены экранные формы с результатами работы лексического анализа тестовой задачи.

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

24

М.Ф.Степанов

Создание распределенной системы решения задач

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

Рисунок 13. Текстовое представление тестовой постановки задачи

Рисунок 14. Результаты лексического анализа. Таблица лексем

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

Методические указания к выполнению курсовой работы

25

 

Системное программное обеспечение

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

Рисунок 15. Результаты лексического анализа. Таблица идентификаторов

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

26

М.Ф.Степанов

Создание распределенной системы решения задач

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

2.10. Разработка синтаксического анализатора входного языка для постановки функциональных задач пользователем

Синтаксический анализатор (синтаксический разбор) – это часть транслятора, которая отвечает за выявление и проверку синтаксических конструкций входного языка. В задачу синтаксического анализа входит:

¾Поиск и выделение синтаксических конструкций в исходно тексте;

¾Установка типа и проверка правильности каждой синтаксической конструкции;

¾Представление синтаксических конструкций в виде, удобном для дальнейшей генерации выходного текста.

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

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

Остальная информация о лексемах используется на более поздних фазах – при семантическом анализе, подготовке к генерации и генерации результирующего выходного текста.

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

На этапе синтаксического анализа требуется более строгое описание синтаксических конструкций, которое часто может быть получено лишь с использованием более сложных КС-грамматик.

В рассматриваемом примере уточним параметры входного языка и для описания его синтаксиса воспользуемся КС-грамматикой.

Вспомним, что на этапе лексического анализа идентификаторы, целые и вещественные числа, разделители (скобки, пробел) выделены как отдельные лексемы и сохранены в таблице лексем. Поэтому на этапе синтаксического анализа рассматривать их терминальные символы не будем.

Проведем анализ типов лексем.

Тогда грамматика входного языка, используемая на этапе синтаксического анализа примет вид:

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

Методические указания к выполнению курсовой работы

27

 

Системное программное обеспечение

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

G2(VT,VN,P, <задача>),

где <задача> - начальный символ грамматики,

VT = {n|A|x|t|k|h|0|1|2|3|4|5|6|7|8|9|.|+|-|[|]|;|,|=| } – словарь терминальных символов, где " " – обозначает пробел,

VN = {<задача> |<>} – словарь нетерминальных символов,

P– правила подстановки:

1:<задача>::=<массивыCразмерностью><началоАнализа><разделитель_";"> <конецАнализа><разделитель_";"><шаг><разделитель_";">

2:<размерность>::=<идентификатор_"n"><равно><целоеЧисло><разделитель_";">

3:<началоАнализа>::=<идентификатор_"t0"><равно><вещественноеЧисло><разделитель_";">

4:<конецАнализа>::=<идентификатор_"tk"><равно><вещественноеЧисло><разделитель_";">

5:<шаг>::=<идентификатор_"h"><равно><вещественноеЧисло>

6:<матрицаА>::=<идентификатор_"A"><равно><матрица><разделитель_";">

7:<векторX0>::= <идентификатор_"x0"><равно><матрица><разделитель_";">

8:<строкиМатрицы>::= <строкиМатрицы><строкаМатрицы><разделитель_";">

9:<строкиМатрицы>::= <строкиМатрицы><строкиМатрицы><строкаМатрицы>

10:<матрица>::=[<строкиМатрицы>]

11:<матрица>::=[<строкаМатрицы>]

12:<строкиМатрицы>::= <строкиМатрицы><строкиМатрицы>

13:<строкиМатрицы>::= <строкиМатрицы><строкаМатрицы>

14:<строкиМатрицы>::= <строкаМатрицы><разделитель_";">

15:<строкаМатрицы>::=<строкаМатрицы><вещественноеЧисло>

16:<массивыCразмерностью>::=<размерность><разделитель_";"><массивы>

17:<массивы>::=<матрицаА><векторX0>

18:<строкаМатрицы>::=<вещественноеЧисло>

19:<строкиМатрицы>::=<строкаМатрицы>

<идентификатор_"n">::=n <идентификатор_"t0">::=t0 <идентификатор_"tk">::=tk <идентификатор_"h">::=h <идентификатор_"A">::=A <идентификатор_"X0">::=x0 <открывающаясяСкобка>::=[ <закрывающаясяСкобка>::=] <разделитель_";">::=; <равно>::==

Пусть для этапа синтаксического анализа необходимо описать входной язык грамматикой предшествования. Такие грамматики используются для синтаксического разбора цепочек входного языка с помощью модификации алгоритма "сдвиг-свертка".

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

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

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

свертка.

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

28

М.Ф.Степанов

Создание распределенной системы решения задач

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

При отсутствии отношения предшествования между символами алгоритм сигнализирует об ошибке.

Необходимо непротиворечивым образом определить отношения предшествования между символами грамматики.

Отношения предшествования будем обозначать знаками "=.", "<.", ".>". Отношение предшествования единственно для каждой пары символов. Если между какими-либо двумя символами не установлено отношение предшествования, то это значит, что они не могут находиться рядом ни в одном элементе синтаксически правильной цепочки.

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

¾Bi <. Bi+1, если символ Bi+1 - крайний левый символ некоторой основы (это отношение можно назвать "предшествует основе" или просто "предшествует");

¾Bi .> Bi+1, если символ Bi - крайний правый символ некоторой основы (это отношение можно назвать "следует за основой" или просто "следует");

¾Bi =. Bi+1, если символы Bi и Bi+1 – принадлежат одной основе (это отношение можно назвать "составляют основу").

Разберем суть принципа разбора входной цепочки αγβδ в тот момент, когда выполняется свертка цепочки γ (см. рис. 16).

н

α

a

 

γ

 

b

β

δ

к

 

 

<.

<.

=.

=.

=.

.>

 

 

 

Рисунок 16. Отношения между символами входной цепочки в грамматике предшествования

Символ a является последним символом подцепочки α, а символ b – первым символом подцепочки β.

Тогда, если в грамматике удастся установить непротиворечивые отношения предшествования, то в процессе выполнения разбора по алгоритму "сдвиг-свертка" можно всегда выполнять сдвиг до тех пор, пока между символом на верхушке стека и текущим символом входной цепочки существует отношение <. или =..

А как только между этими символами будет обнаружено отношение

.>, сразу надо выполнять свертку.

Причем для выполнения свертки из стека следует выбирать все символы, связанные отношением =.. Все различные правила в грамматике предшествования должны иметь различные правые части – это гарантирует непротиворечивость выбора правила при выполнении свертки.

На основании отношений предшествования строится матрица предшествования.

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

Методические указания к выполнению курсовой работы

29

 

Системное программное обеспечение

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

Строки матрицы предшествования помечаются первыми (левыми) символами, столбцы – вторыми (правыми) символами отношений предшествования.

В клетки матрицы на пересечении соответствующих столбца и строки помещаются знаки отношений.

При этом пустые клетки матрицы говорят о том, что между данными символами нет ни одного отношения предшествования.

Выделяются следующие виды грамматик предшествования:

¾Простого предшествования;

¾Расширенного предшествования;

¾Слабого предшествования;

¾Смешанной стратегии предшествования;

¾Операторного предшествования.

Построим матрицу предшествования, воспользовавшись двумя дополнительными типами множеств символов – множествами крайних левых и крайних правых символов, а также множествами крайних левых терминальных и крайних правых терминальных символов для всех нетерминальных символов грамматики.

Для грамматики G(VT,VN,P,S) :

¾L(U)={ T | U * Tz} – множество крайних левых символов относительно нетерминального символа U;

¾R(U)={ T | U * zT} – множество крайних правых символов относительно нетерминального символа U;

¾Lт(U)={ t | U * tz или U * Сtz } – множество крайних левых терминальных символов относительно нетерминального символа U;

¾Rт(U)={ t | U * zt или U * ztC } – множество крайних правых терминальных символов относительно нетерминального символа U,

где U,C VN , T V , z V*, t VТ.

Множества L(U) и R(U) могут быть построены для каждого нетерминального символа U VN по следующему алгоритму:

1.Для каждого U VN ищем все правила, содержащие U в левой части. Во множество L(U) включаем самый левый символ из правой части правил, а во множество R(U) - самый правый символ из правой части. Если

вправой части правила для символа U имеется только один символ, то он должен быть записан в оба множества.

2.Для каждого U VN выполняем следующее преобразование: если множество L(U) содержит нетерминальные символы грамматики U', U'', … , то его надо дополнить символами, входящими в соответствующие множества L(U'), L(U''), … и не входящими в L(U). Аналогичные действия следует выполнить и для R(U).

_____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________

30

М.Ф.Степанов

Соседние файлы в папке Системное программирование