Структура компилятора
Разработка программы для лексического и синтаксического анализа на языке программирования Visual C. Исследование процесса построения таблицы переходов-выходов. Характеристика методов трансляции. Изучение способов построения формальной грамматики.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 16.06.2013 |
Размер файла | 2,0 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
Размещено на http://www.allbest.ru/
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ
САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ АЭРОКОСМИЧЕСКОГО ПРИБОРОСТРОЕНИЯ
КАФЕДРА ИНФОРМАТИКИ И ВЫЧИСЛИТЕЛЬНОЙ ТЕХНИКИ
Курсовой проект
Структура компилятора
Выполнил:
Басковский Д.С.
Пятигорск, 2011.
Введение
Тема курсового проектирования является разработка лексического и синтаксического анализаторов. Объектом исследования является фрагмент кода, написанного на языке программирования Visual C.
Цель проектирования - разработка программы-анализатора.
Задача проектирования:
- Изучение методов трансляции;
- Формирование и описание объекта синтаксического анализа;
- Построение конечного автомата;
- Построение таблицы переходов-выходов;
- Построение дерева синтаксического анализа;
- Построение стека для дерева синтаксического анализа;
- Построение формальной грамматики, левосторонней и правосторонней формальных грамматик;
- Построение программы анализатора для объекта.
Для реализации поставленных задач было проведено исследование методов синтаксического анализа. На основе проведённого исследования составлен объект, к которому будет применён синтаксический анализ.
Для фрагмента построенного объекта проведено построение конечного автомата, построена таблица переходов-выходов и дерево синтаксического анализа.
Результатом исследования является программа-анализатор, которая обрабатывает объект и формирует результирующий файл.
Данное исследование не является исчерпывающим и может быть продолжено с применением готовых пакетов лексического анализа LEX и программы FLEX.
В настоящее время, при всеобщем развитии информационных технологий, существует проблема разработки сложных программных систем. Сложное программное обеспечение, программная инженерия, компонентная разработка ПО, абстракция и уточнение, выделение модулей, разделение ответственности, переиспользование, адекватность интерфейса, полнота интерфейса, минимальность интерфейса, простота интерфейса.
Каждый человек хоть раз написавший какую-либо программу, достаточно хорошо может представить себе, как разработать «небольшую» программу, решающую обычно одну конкретную несложную задачу и предназначенную, чаще всего, для использования одним человеком или узкой группой людей.
Она решает одну четко поставленную задачу в хорошо известных ограничениях (не более 30000 цифр), к тому же, не очень существенную для какой-либо практической или исследовательской деятельности.
Неважно, насколько быстро она работает - на вычисление уходит не более получаса даже на устаревших компьютерах, и этого вполне достаточно.
Ущерб от неправильной работы программы практически нулевой (за исключением возможности обрушения ею системы, в которой выполняются и другие, более важные задачи).
Не требуется дополнять программу новыми возможностями, практически никому не нужно разрабатывать ее новые версии или исправлять найденные ошибки.
В связи со сказанным выше не очень нужно прилагать к программе подробную и понятную документацию - для человека, который ею заинтересуется, не составит большого труда понять, как ею пользоваться, просто по исходному коду.
Выделим следующие сценарии работы или модификации программы:
Надо сделать так, чтобы индексатор мог работать в инкрементальном режиме, читая на входе одну фразу за другой и пополняя получаемый в процессе работы индекс.
Надо сделать так, чтобы индексатор мог игнорировать предлоги, союзы, местоимения, междометия, частицы и другие служебные слова.
Надо сделать так, чтобы индексатор мог обрабатывать тексты, подаваемые ему на вход в виде архивов.
Надо сделать так, чтоб в индексе оставались только слова в основной грамматической форме - существительные в единственном числе и именительном падеже, глаголы в неопределенной форме.
Определим 2 возможных архитектуры разбиения индексатора на два компонента. Один компонент принимает на свой вход входной текст, полностью прочитывает его и выдает на выходе список слов, из которых он состоит. Второй принимает на вход список слов, она выходе выдает его упорядоченный вариант.
Рис. 1. - Диаграмма обработки входного текста:
1. Аналитическая часть
1.1 Структура компилятора
На начальной фазе лексического анализа входная программа, представляющая собой поток литер, разбивается на лексемы - слова в соответствии с определениями языка. Основными формализмами, лежащим в основе реализации лексических анализаторов, являются конечные автоматы и регулярные выражения. Лексический анализатор может работать в двух основных режимах: либо как подпрограмма, вызываемая синтаксическим анализатором для получения очередной лексемы, либо как полный проход, результатом которого является файл лексем.
В процессе выделения лексем лексический анализатор может как самостоятельно строить таблицы объектов (чисел, строк, идентификаторов и так далее), так и выдавать значения для каждой лексемы при очередном к нему обращении. В этом случае таблицы объектов строятся в последующих фазах (например, в процессе синтаксического анализа).
На этапе лексического анализа обнаруживаются некоторые (простейшие) ошибки (недопустимые символы, неправильная запись чисел, идентификаторов и другие).
Центральная задача синтаксического анализа - разбор структуры программы. Как правило, под структурой понимается дерево, соответствующее разбору в контекстно-свободной грамматике языка. В настоящее время чаще всего используется либо LL(1)-анализ (и его вариант - рекурсивный спуск), либо LR(1)-анализ и его варианты (LR(0), SLR(1), LALR(1) и другие). Рекурсивный спуск чаще используется при ручном программировании синтаксического анализатора, LR(1) - при использовании систем автоматического построения синтаксических анализаторов.
Результатом синтаксического анализа является синтаксическое дерево со ссылками на таблицы объектов. Ошибки, связанные со структурой программы, также обнаруживаются в процессе синтаксического анализа. На этапе контекстного анализа выявляются зависимости между частями программы, которые не могут быть описаны контекстно-свободным синтаксисом. Это, в основном, связи "описание-использование", в частности, анализ типов объектов, анализ областей видимости, соответствие параметров, метки и другие. В процессе контекстного анализа таблицы объектов пополняются информацией об описаниях (свойствах) объектов.
Основным формализмом, используемым при контекстном анализе, является аппарат атрибутных грамматик. Результатом контекстного анализа является дерево программы. Информация об объектах может быть как рассредоточена в самом дереве, так и сосредоточена в отдельных таблицах объектов. В процессе контекстного анализа также могут быть обнаружены ошибки, связанные с неправильным использованием объектов.
Затем программа может быть переведена во внутреннее представление. Это делается для целей оптимизации и/или удобства генерации кода. Еще одной целью преобразования программы во внутреннее представление является желание иметь переносимый компилятор. Тогда только последняя фаза (генерация кода) является машинно-зависимой. В качестве внутреннего представления может использоваться префиксная или постфиксная запись, ориентированный граф, тройки, четверки и другие способы.
Фаз оптимизации может быть несколько. Оптимизации обычно делят на машинно-зависимые и машинно-независимые, локальные и глобальные. Определенная часть машинно-зависимой оптимизации выполняется на фазе генерации кода. Глобальная оптимизация пытается принять во внимание структуру всей программы, локальная - только небольших ее фрагментов. Глобальная оптимизация основывается на глобальном потоковом анализе, который выполняется на графе программы и представляет по существу преобразование этого графа. При этом могут учитываться такие свойства программы, как между процедурный анализ, межмодульный анализ, анализ областей жизни переменных и так далее.
Наконец, генерация кода - последняя фаза трансляции. Результатом ее является либо ассемблерный модуль, либо объектный (или загрузочный) модуль. В процессе генерации кода могут выполняться некоторые локальные оптимизации, такие как распределение регистров, выбор длинных или коротких переходов, учет стоимости команд при выборе конкретной последовательности команд. Для генерации кода разработаны различные методы, такие как таблицы решений, сопоставление образцов, включающее динамическое программирование, различные синтаксические методы. Конечно, те или иные фазы транслятора могут либо отсутствовать совсем, либо объединяться. В простейшем случае однопроходного транслятора нет явной фазы генерации промежуточного представления и оптимизации, остальные фазы объединены в одну, причем нет и явно построенного синтаксического дерева.
Рис. 2. - Структура взаимодействия лексического и синтаксического анализа:
1.2 Стадии работы компилятора
Лексический анализатор (англ. lexical analyzer или коротко lexer) - это программа или часть программы, выполняющая лексический анализ. Лексический анализатор обычно работает в две стадии: сканирование и оценка. На первой стадии, сканировании, лексический анализатор обычно реализуется в виде конечного автомата, определяемого регулярными выражениями. В нём кодируется информация о возможных последовательностях символов, которые могут встречаться в токенах. Например, токен «целое число» может содержать любую последовательность десятичных цифр. Во многих случаях первый не пробельный символ может использоваться для определения типа следующего токена, после чего входные символы обрабатываются один за другим пока не встретится символ, не входящий во множество допустимых символов для данного токена. В некоторых языках правила разбора лексем несколько более сложные и требуют возвратов назад по читаемой последовательности.
Полученный таким образом токен содержит необработанный исходный текст (строку). Для того чтобы получить токен со значением, соответствующим типу (напр. целое или дробное число), выполняется оценка этой строки - проход по символам и вычисление значения.
Токен с типом и соответственно подготовленным значением передаётся на вход синтаксического анализатора.
Следующая стадия компиляции синтаксический анализ.
Различаю два вида анализа:
Нисходящий разбор (англ. top-down parser) - продукции грамматики раскрываются, начиная со стартового символа, до получения требуемой последовательности токенов.
Восходящий разбор (англ. bottom-up parser) - продукции восстанавливаются из правых частей, начиная с токенов и кончая стартовым символом.
Метод рекурсивного спуска или нисходящий разбор - это один из методов определения принадлежности входной строки к некоторому формальному языку, описанному LL(k) контекстно-свободной грамматикой. Это класс алгоритмов грамматического анализа, где правила формальной грамматики раскрываются, начиная со стартового символа, до получения требуемой последовательности токенов.
Идея метода:
- для каждого нетерминального символа K строится функция, которая для любого входного слова x делает 2 вещи:
- находит наибольшее начало z слова x, способное быть началом выводимого из K слова;
- определяет, является ли начало z выводимым из K;
- такая функция должна удовлетворять следующим критериям;
- считывать из еще необработанного входного потока максимальное начало A, являющегося началом некоторого слова, выводимого из K;
- определять является ли A выводимым из K или просто не выводимым началом выводимого из K слова.
В случае, если такое начало считать не удается (и корректность функции для не терминала K доказана), то входные данные не соответствуют языку, и следует остановить разбор.
Разбор заключается в вызове описанных выше функций. Если для считанного не терминала есть составное правило, то при его разборе будут вызваны другие функции для разбора входящих в него терминалов. Дерево вызовов, начиная с самой «верхней» функции эквивалентно дереву разбора.
Наиболее простой и «человечный» вариант создания анализатора, использующего метод рекурсивного спуска, - это непосредственное программирование по каждому правилу вывода для не терминалов грамматики.
Синтаксический LL-анализатор - нисходящий синтаксический анализатор для подмножества контекстно-свободных грамматик. Он анализирует входной поток слева направо, и строит левый вывод грамматики. Класс грамматик, для которых можно построить LL-анализатор, известен как LL-грамматики.
Восходящий анализатор (bottom-up parsing) предназначен для построения дерева разбора, начиная с листьев и двигаясь вверх к корню дерева разбора. Мы можем представить себе этот процесс как "свертку" исходной строки w к аксиоме грамматики. Каждый шаг свертки заключается в сопоставлении некоторой подстроки w и правой части какого-то правила грамматики и замене этой подстроки на не терминал, являющийся левой частью правила. Если на каждом шаге подстрока выбирается правильно, то в результате мы получим правый вывод.
В информатике LR-анализатор - синтаксический анализатор для исходных кодов программ, написанных на некотором языке программирования, который читает входной поток слева (Left) направо и производит наиболее правую (Right) продукцию контекстно-свободной грамматики. Используется также термин LR(k)-анализатор, где k выражает количество непрочитанных символов предварительного просмотра во входном потоке, на основании которых принимаются решения при анализе. Обычно k равно 1 и часто опускается.
Заключительная фаза трансляции - семантический анализ, а также фаза синтеза - генерация кода (оптимизация) или интерпретация - привязаны к синтаксису (и, соответственно, к синтаксическому анализатору), поскольку интерпретируют «смысловое» содержание и правила преобразования (или исполнения) элементарных синтаксических единиц, выделенных синтаксическим анализатором. Особенностью семантического анализа является то, что он менее привязан к структуре программы: семантика одного и того же объекта программы может определяться синтаксически не связанными элементами программы. Во-вторых, семантический анализ не формализуем, поскольку семантика программы представляется в процессе трансляции уникальной структурой данных, содержащей описания множеств объектов языка, определенных в программе, их свойств и взаимосвязей (семантические таблицы). Работа с такими таблицами производится через и семантические процедуры, соответствующие элементам синтаксиса (правила грамматики), которые также разрабатываются содержательным образом, не имея под собой формальной основы. Генерация кода и оптимизация также проектируются содержательными методами и содержат много специфических моментов, касающихся особенностей проецирования традиционных объектов языков программирования на элементы архитектуры компьютера (распределение памяти под переменные, распределение регистров под промежуточные результаты и оптимизация их использования и т. п.).
Конечный автомат - абстрактный автомат без выходного потока, число возможных состояний которого конечно. Результат работы автомата определяется по его конечному состоянию.
Существуют различные варианты задания конечного автомата. Например, конечный автомат может быть задан с помощью пяти параметров, где Q - конечное множество состояний автомата, S0 - начальное состояние автомата, F - множество заключительных (или допускающих) состояний, У - допустимый входной алфавит (конечное множество допустимых входных символов), из которого формируются строки, считываемые автоматом, д - заданное отображение множества во множество подмножеств Q.
Автомат начинает работу в состоянии S0, считывая по одному символу входной строки.
Считанный символ переводит автомат в новое состояние из Q в соответствии с функцией переходов. Если по завершении считывания входного слова (цепочки символов) автомат оказывается в одном из допускающих состояний, то слово «принимается» автоматом. В этом случае говорят, что оно принадлежит языку данного автомата. В противном случае слово «отвергается».
Конечные автоматы широко используются на практике, например в синтаксических, лексических анализаторах, и тестировании программного обеспечения на основе моделей.
Диаграмма состояний (или иногда граф переходов) - графическое представление множества состояний и функции переходов.
Представляет собой нагруженный однонаправленный граф, вершины которого - состояния КА, ребра - переходы из одного состояния в другое, а нагрузка - символы, при которых осуществляется данный переход.
Если переход из состояния S1 в S2 может быть осуществлен при появлении одного из нескольких символов, то над дугой диаграммы (ветвью графа) должны быть надписаны все они.
Таблица переходов - табличное представление функции д. Обычно в такой таблице каждой строке соответствует одно состояние, а столбцу - один допустимый входной символ.
В ячейке на пересечении строки и столбца записывается действие, которое должен выполнить автомат, если в ситуации, когда он находился в данном состоянии на входе он получил данный символ.
Формальная грамматика или просто грамматика в теории формальных языков - способ описания формального языка, то есть выделения некоторого подмножества из множества всех слов некоторого конечного алфавита. Различают порождающие и распознающие (или аналитические) грамматики - первые задают правила, с помощью которых можно построить любое слово языка, а вторые позволяют по данному слову определить, входит оно в язык или нет.
1.3 Термины
Терминал (терминальный символ) - объект, непосредственно присутствующий в словах языка, соответствующего грамматике, и имеющий конкретное, неизменяемое значение (обобщение понятия «буквы»). В формальных языках, используемых на компьютере, в качестве терминалов обычно берут все или часть стандартных символов ASCII - латинские буквы, цифры и спец. символы.
Не терминал (нетерминальный символ) - объект, обозначающий какую-либо сущность языка (например: формула, арифметическое выражение, команда) и не имеющий конкретного символьного значения.
1.4 Процесс вывода
Выводом называется последовательность строк, состоящих из терминалов и не терминалов, где первой идет строка, состоящая из одного стартового не терминала, а каждая последующая строка получена из предыдущей путем замены некоторой подстроки по одному (любому) из правил. Конечной строкой является строка, полностью состоящая из терминалов, и следовательно являющаяся словом языка.
Существование вывода для некоторого слова является критерием его принадлежности к языку, определяемому данной грамматикой.
2. Техническое задание
В качестве объекта исследования берется фрагмент кода написанный на языке C. Данный объект содержит объявление процедуры main, определение переменной целочисленного типа, и вычисление арифметических операций.
Данный код выполняет простое условие - находит максимальное значение элемента из данных.
Для разбора данного объекта проведем следующие стадии компиляции:
- лексический анализ;
- синтаксический анализ;
Для лексического анализа необходимо:
- разработать конечный автомат для арифметической операции;
- по конечному автомату составим таблицы переходов и выходов.
Для синтаксического анализа необходимо:
- разработать формальный язык;
- по данному формальному языку разработать правила для арифметических операций.
Для грамматики:
- построить дерево синтаксического анализа;
- стек.
Для разбора грамматик будем использовать:
- левосторонний разбор;
- правосторонний разбор.
Объект исследования разделить на:
- лексемы;
- присвоить идентификатор каждой лексеме;
- определить ее тип.
Для арифметических операций необходимо определить:
- свойства арифметических операций;
- приоритеты арифметических операций;
- составить грамматику для арифметических операций;
- определить правила построения выражений.
Разработать программу для анализа входного объекта.
Программное обеспечение должно выполнять следующие функции:
- считать из входного файла объект;
- проанализировать данный объект;
- создать выходной файл содержащий результат работы анализатора.
Входной файл содержит объект анализа данный объект представлен в виде фрагмента кода. Выходной файл содержит лексемы входного объект, их тип и идентификаторы. Точкой входа приложения служит структура «void Main()».
Тип данных то некоторый класс объектов данных вместе с набором операций для создания и работы с ними. Существуют три спецификации типа данных: атрибуты, значения и операции. Переменная - это объект данных, который явным образом определен и именован в программе. В данной программе использовались простые переменные - именованный элементарный объект данных. Все объекты в C# принадлежат к классу Object.
Операция присваивания «=» - это операция связывания объекта данных со значением. «Int» (Integer), т.е. объявлена переменная целочисленного типа, которая занимает в памяти 4 байта. Это наиболее распространенный элементарный тип.
Ключевые слова - это имена, имеющие особое значение только в определенном контексте. В данной программе ключевым словом выступает условный оператор «if».
Условный оператор «IF»:
Это одновариантный условный оператор. Семантика выполнения заключена в следующем: вычисляется логическое выражение, если же выражение истинно, выполняется первый оператор, если оно ложно, оператор не выполняется и управление переходит к следующему оператору.
Оператор «ELSE IF» в большинстве языков программирования таков, что оператор, следующий за ключевым словом «else» всегда относится к ближайшему предшествующему оператору.
В данной программе использовалась логическое выражение «И», которая на языке программирования C имеет вид «&&»
2.1 Формальная грамматика для элементов объекта
Теперь приведем формальное определение КА в терминах дискретной математики и теории множеств. Конечный автомат определяется шестью компонентами.
Опишем, как выглядит работа такой системы:
- КА является дискретной системой, работающей по тактам (шагам), в каждом из которых он получает на вход один из символов входного алфавита;
- Последовательность символов на входе КА образует входную цепочку;
- На каждом шаге КА находится в одном из возможных состояний, которое называется текущим. Текущее состояние - единственная характеристика внутреннего описания КА, которая меняется при его работе (изменяемая память). Все остальные элементы его описания являются статическими (т. е. в любой реализации представляют собой постоянную память);
- Шаг работы КА состоит в переходе из текущего состояния в новое состояние при получении на вход очередного символа входной цепочки. Этот переход определяется функцией переходов;
- Результат работы КА заключается в записи в выходную цепочку символов, генерируемых функцией выходов КА. Т.е. параллельно с переходом в новое состояние формируется выходной символ, определяемый парой «текущее состояние - входной символ». Выходной символ может быть и пустым;
- Работа КА заключается в преобразовании входной цепочки символов в выходную. Закон этого преобразования определяет поведение КА. Задача проектирования КА состоит в создании КА, обеспечивающем заданные правила преобразования цепочек.
Очевидно, что отсутствие у КА внутренней памяти ограничивает его возможности по преобразованию цепочек (общепринятый термин - моделирующая способность). С другой стороны, эти же ограничения позволяют решать в общем случае многие проблемы (термин - алгоритмическая разрешимость, т. е. принципиальная возможность разработать соответствующий алгоритм).
Хотя автоматы и можно представить в традиционной для алгоритма технологии блок-схем (управляющие КА так и строятся на основе разметки блок-схемы алгоритма), наиболее удобной формой их представления для человека является графическая - диаграмма состояний-переходов, а для программирования и формальных преобразований - табличная. Основные элементы диаграммы состояний - переходов:
- Состояние представляет собой окружность, содержащую номер или наименование состояния;
- Направленная дуга, соединяющая состояния Sk и Sm, определяется значениями функций переходов и действий, если:
Sm=P (Sk,Ii)
On=D (Sk,Ii)
В таком случае имеется переход КА из Sk в Sm , который обозначается дугой, соединяющей эти вершины. Дуга подписывается парой символов IiOn. Это означает, что переход по дуге при поступлении на вход символа Ii сопровождается формированием выходного символа On.
Если поведение какого-либо объекта можно описать набором предложений вида: «Находясь в состоянии A, при получении сигнала S объект переходит в состояние B и при этом выполняет действие D», то такая система будет представлять собой конечный автомат.
P |
; |
е |
|
S0 |
1 |
0 |
|
S1 |
2 |
2 |
P |
; |
е |
|
S0 |
1 |
0 |
|
S1 |
2 |
2 |
P |
> |
< |
|
S0 |
1 |
0 |
|
S1 |
2 |
2 |
|
S2 |
1 |
0 |
|
D |
I |
F |
|
S0 |
E |
||
S1 |
Z |
||
S2 |
Z |
P |
I |
F |
|
S0 |
1 |
0 |
|
S1 |
2 |
2 |
|
S2 |
1 |
0 |
D |
I |
F |
|
S0 |
X |
||
S1 |
X |
||
S2 |
O |
Анализируя приведенный здесь пример диаграммы состояний-переходов и вид преобразования цепочек, можно сделать вывод о поведении автомата и сущности выполняемых им преобразований. Нетрудно заметить, что получая входные цепочки, содержащие символы a и b в произвольном порядке, КА формирует аналогичные цепочки более регулярного вида. Так, из подряд идущих символов b он оставляет один, а в последовательности символов a оставляет все нечетные, кроме первого.
3. Проектная часть
3.1 Функциональное описание
Для арифметических операций определим их свойства и приоритеты.
Арифметические операции.
«+»-плюс- арифметическая операция сложения двух и более чисел a+b, приоритет операции 2.
«-»-минус - арифметическая операция вычитания двух и более чисел a-b, приоритет операции 2.
«*»-умножение - арифметическая операция умножения двух и более чисел a*b, приоритет операции 1.
«/»-деление - арифметическая операция деления одного числа на другое a/b, приоритет операции 1.
Объявление переменных: Переменная в традиционных (императивных) языках программирования - поименованная либо адресуемая иным способом область памяти, имя или адрес которой можно использовать для осуществления доступа к данным, находящимся в переменной (по данному адресу).
Определим набор лексем языка, обозначим тип каждой лексемы, опишем каждую лексему.
Лексема |
Тип лексемы |
Описание |
|
void, int |
Идентификатор |
Определители, определяют тип переменных функций. |
|
main |
Идентификатор |
Ключевая лексема определяет начало программы. |
|
( ) { } . , ; |
Разделители. |
Разделяют предложения на лексемы. |
|
Натуральное число |
Константа |
Последовательность символов, состоящая только из цифр и не начинающаяся с нуля. |
|
If else |
Системная лексема |
Логические операции. |
|
= |
Системная лексема |
Оператор присвоения. |
|
Идентификатор |
Последовательность символов, не начинающаяся с цифры. |
3.2 Построение конечного автомата
Для определения входной строки разработаем конечный автомат.
Рис 4. - Граф конечного автомата:
Входная строка анализа:
По графу конечного автомата построим таблицы переходов и выходов.
Таблица - переходы:
P |
a |
b |
c |
d |
& |
|
S0 |
1 |
0 |
0 |
0 |
0 |
|
S1 |
0 |
2 |
0 |
0 |
0 |
|
S2 |
0 |
0 |
3 |
0 |
0 |
|
S3 |
0 |
0 |
0 |
4 |
0 |
|
S4 |
- |
- |
- |
- |
Выход |
Таблица - выходы:
D |
a |
b |
c |
d |
& |
|
S0 |
< |
- |
- |
- |
- |
|
S1 |
- |
if |
- |
- |
- |
|
S2 |
- |
- |
< |
- |
- |
|
S3 |
- |
- |
- |
if |
- |
|
S4 |
- |
- |
- |
- |
Выход |
3.3 Определение формальной грамматики
Определим для арифметических операций формальную грамматику.
Терминальный алфавит:
Нетерминальный алфавит:
Правила грамматики.
Таблица:
ФОРМУЛА::ФОРМУЛА ЗНАК ФОРМУЛА |
формула есть две формулы, соединенные знаком |
|
ФОРМУЛА::ЧИСЛО |
формула есть число |
|
ФОРМУЛА::( ФОРМУЛА ) |
формула есть формула в скобках |
|
ЗНАК::< > = ! |
знак есть меньше или больше или равно или не равно |
|
ЧИСЛО::ЦИФРА |
число есть цифра |
|
ЧИСЛО::ЧИСЛО ЦИФРА |
число есть число и цифра |
|
ЦИФРА::0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
цифра есть 0 или 1 или ... 9 |
Определим множество:
- «ФОРМУЛА» как F;
- «ЧИСЛО» как C;
- «ЦИФРА» как E;
- «ЗНАК» как K;
Правила формальной грамматики арифметической операций построим следующим образом:
Построим формальную грамматику для выражения:
3.4 Построение дерева синтаксического анализа
Дерево разбора арифметических действий:
Дерево формального разбора грамматики.
Таблица - дерево синтаксического разбора построим стек:
18 |
A |
13 |
|
17 |
E |
12 |
|
16 |
T |
11 |
|
15 |
) |
9 |
|
14 |
Z |
10 |
|
13 |
( |
9 |
|
12 |
E |
8 |
|
11 |
A |
10 |
|
10 |
E |
9 |
|
9 |
= |
9 |
|
8 |
Z |
8 |
|
7 |
F |
6 |
|
6 |
a |
6 |
|
5 |
E |
4 |
|
4 |
< |
5 |
|
3 |
Z |
4 |
|
2 |
T |
2 |
|
1 |
Z |
1 |
|
0 |
R |
0 |
Правила формальной грамматике для объявления переменных:
3.5 Синтаксические алгоритмы разбора
Определим формальную грамматику для восходящего разбора:
Z:E#
E:TM
E:if FE
E:else FE
M:<TM
M:>TM
M:
T:FG
G:==FG
G:!=FG
G:
F:(E)
F:aY
F:c
Y:[E]
Y:(L
Y:
L:)
L:EN)
N:
N:,EN
Определение формальной грамматики арифметических операций:
Z:E# select:(4 6 -3
E:TM select:(4 6 -3
M:<TM select:<
M:>TM select:>
M: select:#)]
T:FG select:(a b c d
G:FG select:
G:!=FG select:!
G: select:-+#)]
F:(E) select:(
F:4Y select:4
F:6Y select:6
Y:[E] select:[
Y:(L select:(
Y: select:*/-+#)]
L:EN) select:(4 6 -3
N: select:)
NTS::ZEMTGFYLN; множество не терминальных символов
TS::#-+*/()abcd[]; множество терминальных символов
Последовательность действий магазинного автомата (МА) (состояние стека и входной строки, номер применяемого правила).
stack |
input |
rule |
|
E# |
b<a |
E:TM |
|
TM# |
c<a |
T:FG |
|
FGM# |
a<b |
F:1Y |
|
cbYGM# |
c<b |
POP symbol:1 |
|
YGM# |
c<a |
Y: |
|
GM# |
b<a |
G: |
|
M# |
d=a# |
M:+TM |
|
dbTM# |
d=b# |
POP symbol:+ |
|
TM# |
d=c# |
T:FG |
|
4FGM# |
a=4# |
F:2Y |
|
6YGM# |
b=6# |
POP symbol:2 |
|
-3YGM# |
c=-3# |
Y: |
|
dGM# |
d# |
POP symbol:3 |
|
GM# |
# |
G: |
|
M# |
# |
M: |
|
# |
# |
3.6 Отношение предшествования
Построить отношение предшествования:
- перечислить отношения предшествования, следующие их каждого правила,
- заполнить таблицу предшествования, указав около каждого элемента отношения номер правила, из которого оно следует.
3.7 Нисходящий разбор
Формальная грамматика для нисходящий разбора:
Z:E#
E:E<T
E:E>T
E:T
T:T==F
T:T!=F
T:F
F:d
F:a
F:b
F:c
F:a[E]
F:4
F:6
F:-3
L:LE,
NTS::ZETFL
TS::#-+*/a()[]123.
Таблица - Управляющая таблица для LL-анализатора:
D |
# |
- |
+ |
* |
/ |
1 |
2 |
3 |
|
# |
|||||||||
== |
< |
< |
< |
||||||
!= |
< |
< |
< |
||||||
< |
< |
< |
< |
||||||
> |
< |
< |
< |
||||||
1 |
> |
> |
> |
> |
> |
||||
2 |
> |
> |
> |
> |
> |
||||
3 |
> |
> |
> |
> |
> |
||||
F |
> |
> |
> |
> |
> |
||||
T |
> |
> |
> |
= |
= |
||||
E |
= |
= |
= |
< |
< |
< |
Для выбранного правильного предложения записать последовательность действий магазинного автомата (МА) (состояние стека и входной строки, действие - перенос или свертка с номером правила, по которому она производится).
reduce |
rule |
stack |
input |
|
>E|+ |
F:1 |
F |
+4# |
|
>F|+ |
T:F |
T |
+6# |
|
>T|+ |
E:T |
E |
-3# |
|
< |
E |
{a b c}|d# |
||
== |
E==d |
{ a b c}|d# |
||
!= |
F:2 |
E!=d |
{ a b c}|d # |
|
>if E<F|* |
T:F |
E+T |
d# |
|
>else E>F|* |
E+T* |
!d# |
||
>E+T|# |
E:E+T |
E |
# |
|
=# |
E# |
|||
>E#| |
Z:E# |
Z |
Понятно, что любая задача преобразования цепочек символов в рамках любой грамматики может быть решена путем полного перебора всех возможных вариантов подстановок, что влечет за собой экспоненциальную (показательную) трудоемкость решения задачи, не приемлемую в реальных условиях. Любой человек, использующий транслятор, в праве ожидать, что последний не слишком уменьшает скорость работы при росте объема транслируемой программы (то есть трудоемкость близка к линейной). Для этого прежде всего требуется отказаться от «тупого» перебора вариантов подстановки с возвратами к промежуточным цепочкам и обеспечить на каждом шаге выбор единственно правильного направления движения из нескольких возможных (так называемый жадный алгоритм).
Теперь следует разобраться, в каких взаимоотношениях находятся формальные грамматики и синтаксический анализ. Синтаксис любого языка программирования определяется контекстно-свободной формальной грамматикой - системой терминальных и нетерминальных символов и множеством правил. Анализируемая программа представляется в такой грамматике предложением языка. Задача синтаксического анализа - определить, является ли это предложение правильным и построить для него последовательность непосредственных выводов из начального символа Z, или синтаксическое дерево.
Сам процесс построения дерева, равно и синтаксического анализа может быть как нисходящим, т. е. от вершины-предка к вершинам-потомкам с заменой левых частей правил на правые и наоборот, восходящим.
В этом же контексте объясняется понятие синтаксической ошибки. Если на каком-то этапе построения синтаксического дерева встречается недопустимая или тупиковая ситуация, то построенная последовательность терминальных символов соответствует синтаксически правильной части программы, а очередной «незакрытый» терминальный символ локализуется как синтаксическая ошибка.
4. Технологическая часть
Входными данными является файл входных данных, содержащий объект анализа. Объект построчно загружается в оперативную память. Каждая строка анализируется с помощью смоделированного программным путем конечного автомата. Конечный автомат разбивает строку на элементарные лексемы, определяет тип лексемы, и идентификатор лексемы.
Входные данные:
- входной файл, хранящий объект исследования;
- набор лексем входного языка.
После выполнения анализа программа генерирует выходной файл содержащий лексемы объекта, идентификатор каждой лексемы, тип лексемы. Анализатор самостоятельно определяет имена переменных, и далее при анализе определяет данный идентификатор как системную лексему.
Лексема записана в файл в виде:
Лексемы в файле находятся в прямой последовательности лексем объекта.
Работа проводилась на языке C вместе с NET Framework версии 4.0.
Программа написана на интерфейсе Windows Forms. Windows Forms - название интерфейса программирования приложений (API), отвечающего за графический интерфейс пользователя и являющегося частью Microsoft .NET Framework.
Данный интерфейс упрощает доступ к элементам интерфейса Microsoft Windows за счет создания обертки для существующего Win32 API в управляемом коде.
Главное меню программы.
Рисунок:
Работы программы (функция GO READ).
Рисунок:
Меню “О программе”.
Рисунок:
Входной файл input.txt.
Рисунок:
Выходной файл output.txt.
Рисунок:
Заключение
В ходе курсового проектирования выполнена разработка программы - анализатора фрагмента кода на языке C.
В первой части выполнено исследование методов лексического и синтаксического анализа. Показана методология построения конечного автомата, синтаксического дерева, формальной грамматики, левостороннего и правостороннего разбор.
На основании проведенного исследована составлено техническое задание в соответствии с котором необходимо для конкретного объекта составить конечный автомат, синтаксическое дерево, формальную грамматику, применить методы левостороннего и правостороннего разборов и написать программу-анализатор.
Во второй части более подробно рассматривается объект применительно к которому проводится весь дальнейший анализ. Объект разбирается на лексемы, описывается смысл назначение каждой лексемы. Далее для фрагмента кода строится конечный автомат и таблица переходов-выходов. Составлена формальная грамматика, построено синтаксическое дерево, проведены нисходящие и восходящие разборы, составлены соответствующие таблицы магазинных автоматов.
В третьей части дано описание программы - анализатор. Описаны выходной и выходной файл программы, алгоритм работы программы, составлена инструкция по работе с программой.
Та ким образом в ходе работы показано применение методов лексического, синтаксического и семантического анализов.
Список литературы
1. Т. Кормен, Ч. Лейзерсон, Р. Ривест. Алгоритмы: построение и анализ. М.: МЦНМО, 1999.
2. И. Соммервилл. Инженерия программного обеспечения. М.: Вильямс, 2002.
3. Е.А. Жоголев. Лекции по технологии программирования: Учебное пособие. М.: Издательский отдел факультета ВМиК МГУ, 2001.
4. Г. Буч. Объектно-ориентированный анализ и проектирование с примерами приложений на C++. Второе издание. М.: Бином, СПб.: Невский диалект, 2000.
5. F. Buschmann, R. Meunier, H. Rohnert, P. Sommerlad, M. Stal. Pattern-Oriented Software Architecture. Wiley, 2002.
6. Э.Дж. Брауде. Технология разработки программного обеспечения. СПб.: Питер, 2004.
Приложение
программирование visual грамматика
Рисунок - Листинг программы:
Размещено на Allbest.ru
...Подобные документы
Разработка анализирующей части компилятора для выполнения проверки исходной программы на соответствие грамматике языка, правилам семантики и построения внутреннего представления. Описание анализаторов: лексического, синтаксического и семантического.
контрольная работа [704,9 K], добавлен 01.02.2013Содержательная часть языка программирования С++. Правила автоматной грамматики, классификация Хомского. Принцип построения графов, разработка проекта средствами среды программирования Builder C++. Алгоритм синтаксического анализа оператора вывода.
контрольная работа [228,4 K], добавлен 22.05.2012Функции компилятора как системной обрабатывающей программы. Этапы компиляции: анализ и синтез. Разработка лексического анализатора. Алгоритм и программа лексического анализа. Реализация двухфазного компилятора. Описание логической структуры программы.
курсовая работа [310,4 K], добавлен 26.03.2010Структура, классификация и требования к реализации компилятора. Проектирование и реализация анализирующей части компилятора языка С++. Способы реализации лексического анализа. Алгоритм работы синтаксического анализатора. Принципы программной реализации.
курсовая работа [774,2 K], добавлен 26.01.2013Изучение принципов построения линейных алгоритмов и простых расчетных программ на языке программирования C. Разработка программы расчета математических выражений на основе вводимых данных. Создание консольных приложений в среде Microsoft Visual Studio.
лабораторная работа [254,4 K], добавлен 23.11.2014Разработка учебного транслятора на языке программирования C# в среде объектно-ориентированного программирования Visual Studio 2012. Выделение лексем и построение цепочки символов на этапе синтаксического анализа. Функциональное тестирование программы.
курсовая работа [406,8 K], добавлен 07.08.2013Основные концепции языков программирования, механизмы типизации данных. Описание языков программирования и методов трансляции. Конечные автоматы и преобразователи. Общие методы синтаксического анализа. Формальные методы описания языкового перевода.
курс лекций [5,5 M], добавлен 04.12.2013История создания и развитие Pascal. Особенности пакета программирования Turbo. его возможности редактора текстов, компилятора и отладчика. Построения программы на языке Turbo Pascal, ее структура, типы алгоритмов, одномерные и многомерные массивы.
курсовая работа [519,3 K], добавлен 25.06.2011Изучение устройства и механизма процессов в компиляторах и интерпретаторах. Понятие трансляции как процедуры перевода программного кода с языка Паскаль на язык С++. Описание интерфейса программы и автоматизация процесса построения диаграммы классов.
курсовая работа [536,2 K], добавлен 03.07.2011Место компилятора в программном обеспечении. Принципы работы и автоматизация построения синтаксического анализатора. Дерево разбора и его преобразование в дерево операций. Назначение и этапы семантического анализа. Идентификация языков программирования.
реферат [265,1 K], добавлен 20.12.2007Входная грамматика в структурированной форме. Функции переходов символьного преобразователя. Работа лексического анализатора. Структуры данных, символы действия. Описание семантики перевода. Построение и программная реализация атрибутного преобразователя.
курсовая работа [128,9 K], добавлен 03.07.2013Создание алгоритма для построения синтаксического анализатора полиномов и его реализация в среде Visual Studio 2005 на языке программирования C#. Программное решение задачи поиска максимального числа единиц в бинарном представлении простых чисел.
курсовая работа [723,5 K], добавлен 04.10.2010Исследование теоретических аспектов разработки программы посредством использования Visual Basic. Анализ достоинств и недостатков данного языка программирования. Изучение особенностей создания интерфейса приложения. Основные этапы реализации программы.
практическая работа [460,6 K], добавлен 22.01.2013Характеристика основных разделов программирования, изучаемых в курсе программирования на языке С++. Описание внутренних переменных, входных и выходных данных. Особенности использования компилятора Microsoft Visual Studio 2008. Руководство пользователя.
курсовая работа [18,8 K], добавлен 14.12.2010Общие сведения о работе программы в среде программирования Microsoft Visual Studio 2008, на языке программирования C++. Ее функциональное назначение. Инсталляция и выполнение программы. Разработанные меню и интерфейсы. Алгоритм программного обеспечения.
курсовая работа [585,5 K], добавлен 24.03.2009Детерминированная автоматная модель синтаксического анализатора. Исследование структуры разработанной программы, требования к функциональности, Основные элементы и принципы реализации. Листинг спроектированной программы и анализ полученных результатов.
курсовая работа [69,1 K], добавлен 11.12.2015Порядок описание процесса разработки модели для разрешения задачи программирования с помощью средств языка программирования. Структуры данных и основные принципы их построения. Этапы компьютерного моделирования. Этапы и значение написания программы.
курсовая работа [19,5 K], добавлен 19.05.2011Изучение алгоритма рекурсивного спуска и системы построения грамматики с помощью лексического анализатора Lex. Написание программы интерпретатора языка разметки HTML. Проверка входной последовательности на корректность входа как общая функция программы.
контрольная работа [226,7 K], добавлен 25.12.2012Техника создания графики при помощи API функций, экспортируемых библиотекой GDI32.DLL. Разработка на языке программирования С++ в среде программирования Microsoft Visual C++ программы для отображения часов реального времени в цифровом и аналоговом виде.
курсовая работа [2,8 M], добавлен 27.01.2010Программная реализация синтаксического анализатора произвольного текста. Матрица и дерево переходов для программы. Код программы с построчным комментарием. Порядок запуска среды разработки Visual Studio. Интерфейс и номера Лихтенштейна, скриншот.
контрольная работа [855,1 K], добавлен 13.02.2014