Автор: Пользователь скрыл имя, 20 Ноября 2012 в 23:12, курсовая работа
Посредством среды разработки «Borland C++ Builder6» осуществляется создание варианта программы-транслятора с одного языка высокого уровня на другой. Созданная программа имеет возможность находить некоторые лексические и синтаксические ошибки, которые могут быть допущены в исходном текстовом файле, предназначенном для трансляции и сообщать о них пользователю.
1. Пояснительная записка………………………………………………………..2
1.1. Задание на проектирование…………………………………………..2
1.2. Содержание…………………………………………………...……….3
1.3. Введение………………………………..………………………………4
1.4. Описание процесса решения задачи…………………………………5
1.5. Блок-схемы основной программы и процедур…………………….15
2. Распечатка программных модулей………………………………………….17
3. Описание программы………………………………………………………...39
3.1. Назначение и общее описание программы………………………...39
3.2. Описание логической структуры программы…………………… ..39
3.3. Способ обращения к программе……………………………………40
3.4. Перечень технических средств………………………………… …..40
4. Описание входных и выходных данных……………………………………40
5. Тестовые примеры работы программы………………..……………………41
Федеральное агентство по образованию
ТАМБОВСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
Кафедра САПР
ПОЯСНИТЕЛЬНАЯ ЗАПИСКА
к курсовой работе по дисциплине «ЛПО САПР»
на тему: «Разработка трехпроходного транслятора
с исходного языка на язык ПЛ-1»
Выполнил: студент группы ССП-21
Галанин М.О.
Проверил: доцент кафедры САПР
Коробова И. Л.
Тамбов 2012
1.1 Задание на проектирование
Вариант №3.
Разработать трехпроходный транслятор с исходного языка на язык ПЛ-1:
program g;
vаг u, v, max. min: real;
begin
read(u,v);
max:=10;
min:=0;
if u>v then
begin
if u>max then max:=u;
if v<min then min:=v
end
else
begin
if v>max then .max:=v;
if u<min then min:=u
end;
write(max,min)
end.
Дата принятия задания к исполнению: 27.02.2012 .
Подпись студента:__ ______________________
1.2. Содержание
1. Пояснительная записка………………………………………………………..
1.1. Задание на проектирование……………
1.2. Содержание………………………………………………….
1.3. Введение………………………………..……………………
1.4. Описание процесса решения задачи…………………………………5
1.5. Блок-схемы основной программы и процедур…………………….15
2. Распечатка программных модулей………………………………………….17
3. Описание программы………………………………
3.1. Назначение и общее
описание программы………………………...
3.2. Описание логической структуры программы…………………… ..39
3.3. Способ обращения к программе……………………………………40
3.4. Перечень технических средств………………………………… …..40
4. Описание входных
и выходных данных…………………………………
5. Тестовые примеры работы программы………………..……………………41
1.3. Введение
Цель данной курсовой работы – закрепление навыков создания лингвистического программного обеспечения САПР, описание языка с помощью формальной грамматики, разработка алгоритма трансляции и реализация простого варианта транслятора, изучение синтаксического анализа методом рекурсивного спуска.
Посредством среды разработки «Borland C++ Builder6» осуществляется создание варианта программы-транслятора с одного языка высокого уровня на другой. Созданная программа имеет возможность находить некоторые лексические и синтаксические ошибки, которые могут быть допущены в исходном текстовом файле, предназначенном для трансляции и сообщать о них пользователю.
1.4. Описание процесса решения задачи
На первом этапе решения задачи была построена грамматика исходного языка в форме Бекуса Наура:
Оператор – >program/ <раздел переменных>/ begin/< оператор цикла> / <запись> / <чтение> /<присваивание>/ end
<раздел переменных>->var<
<список переменных>->ид {,<идентификатор>}
<тип>->integer/real
<ввод>-> read (<список переменных>)
<вывод>-> write( <список переменных>)
<присваивание>-><ид>:= <выражение>
< арифметическое выражение > → <слагаемое> {+/-<слагаемое>}
<логическое выражение> → <идентификатор> < “>” >/<”<”> <константа>
< условие> → if < логическое выражение > than begin <оператор> end else<оператор> end;
<слагаемое> → <множитель> {*или / <множитель>}
<множитель> → <идентификатор> / <константа>
Лексический анализ.
Лексический анализатор реализован с помощью функции READCODE. В этой функции программа считывает построчно информацию из входного файла, затем записывает её в строковый массив dt. Количество строк в массиве фиксировано.
После записи исходной программы в строковый массив происходит посимвольный анализ текста, вначале разбираются арифметические операторы, знаки отношения, скобки и т.д., затем если функция isalpha() возвращает ненулевое значение (т.е. обнаруживается буква) происходит считывание неизвестной символьной конструкции в отдельный массив. Начало и конец этой конструкции, её положение относительно массива символов исходной программы, запоминается и посылается в функцию SELECTLEX(). В ней происходит сравнение неизвестного слова с рядом заданных терминальных символов: операторов, отношений в неравенствах (конструкции вида .ge., т.е. знаки больше, меньше, равно и т.д.) и типов данных (в данном случае их три – real, integer). В случае, если неизвестная функция оказывается равноценной по отношению к одному из этих терминальных символов (сравнение производится с помощью стандартной функции strcmp), то возвращается некое число, использующееся далее в основной функции. В противном случае ясно, что имеем дело с идентификатором, поэтому возвращаем значение 99.
Следующим шагом функции READCODE() является запись в специальный числовой массив соответствующей лексемы. Как выше уже описаны, сначала рассматриваются терминальные символы, затем происходит анализ буквенных конструкций. В зависимости от результата функции SELECTLEX(), мы записываем в массив либо код лексемы оператора, либо отношения неравенства, либо типа. В случае, если функция сообщает нам о наличие неизвестной конструкции (мы предполагаем, что это идентификатор), то выполняется отдельный участок кода, анализирующий данную конструкцию. Вначале мы считываем в отдельный символьный массив имя идентификатора.
Важным моментом данной программы
является способ записи констант и
идентификаторов в таблице
Рассмотрим процесс записи
идентификатора в таблицу символов.
Для временных нужд создается
буфер класса Ident - Buf, в него записывается
считанные символы имени
После определения типа он записывается в поле type объекта Buf (в противном случае он остается неизвестным). Теперь крайне важно проверить, не был ли объявлен этот идентификатор ранее. На данном этапе эта проверка еще не является синтаксической, но позволяет прописать тип уже определенным переменным. Как видно из алгоритма, если использовать уже объявленную переменную далее в тексте кода, то она получит тип «unknow», что в дальнейшем приведет к грубейшей ошибке. Поэтому мы сравниваем элемент Buf со всеми объектами массива ID[MAX], в случае совпадения имени идентификатора происходит следующее:
В первом случае, если тип новой переменной неизвестен, то ясно, что в исходном коде просто используется уже объявленная переменная, поэтому её тип присваивается в Buf.type.
Второй вариант – типы
новой переменной известен и отличен
(исключая первый случай) от уже объявленной,
либо они обе имеют одинаковый
тип. Это может означать только одно
– мы повторно объявили идентификатор
либо с разными типами данными, либо
с одинаковым, но и то, и другое
является ошибкой, поэтому мы запишем
новый идентификатор в
В случае с константами процесс записи похож, только отсутствует проверка на тип. С помощью функции isalpha() и пользуясь таблицей ASCII, мы определяем допустимые для константы символы (цифры и точку) и записываем её в символьный массив. В случае если раньше уже использовалась подобная константа, новый объект класса не затрагивается (ситуация аналогична как и в случае с идентификаторами), и записываются соответствующие лексемы.
Подводя итог, стоит отметить несколько важных пунктов:
- Идентификаторы и константы
заносятся в разные таблицы,
учитывается их имя (также тип
для идентификатора) и порядковый
номер, одинаковые по имени
и типу элементы не получают
новых обозначений, в
- Для идентификаторов
и констант используется
При завершении работы функция создает два файла и записывает в них последовательность лексем (в lexem.txt – просто лексемы, в lexemdebug.txt – лексемы с обозначениями их позиций в массиве).
Для записи лексем используется таблица, приведенная ниже, в ней описаны основные терминальные конструкции исходного языка, обозначения в виде лексем и для справки – аналоги этих конструкций в языке Бейсик:
Терминальный символ (Паскаль) |
Обозначение |
Терминальный символ (pl1) |
program |
1 |
main |
var |
2 |
dcl () dec; |
begin |
3 |
Do |
end |
4 |
End |
writeln |
25 |
putlist |
read |
26 |
getlist |
if |
5 |
if |
then |
6 |
then |
else |
7 |
else |
< |
8 |
< |
> |
9 |
> |
( |
10 |
( |
) |
11 |
) |
* |
12 |
* |
/ |
13 |
/ |
+ |
14 |
+ |
- |
15 |
- |
, |
16 |
, |
; |
17 |
; |
: |
18 |
: |
:= |
19 |
= |
Тип 1 - integer 2 - real |
20+ID типа |
Тип 1 - fixed 2 - float |
Идентификатор |
21+ID ид. |
Аналогично исходному языку |
Константа |
22+ID константы |
Аналогично исходному языку |
:= |
19 |
= |
. |
24 |
. |
В случае, если распознанная конструкция не является ни одной из представленных в таблице, то она определяется, как константа/идентификатор по выше приведенному алгоритму, при этом идентификатор кодируется как 21 + целое число, тип данных – 20 + обозначение типа, код константы – 22 + номер (но не значение!) константы соответственно. После чего происходит их сохранение в массивах ID или CNST.
Лексический анализатор не
выдает ошибок, обозначая неизвестные/
Синтаксический анализ.
Затем начинается синтаксический анализ, в качестве метода синтаксического анализа используется метод рекурсивного спуска. Этот метод относится к нисходящим методам, которые начинают работу с корня грамматического дерева. Процесс грамматического разбора для этого метода состоит из отдельных процедур для каждого нетерминального символа, определенного в грамматике, при этом основной является функция ANALIS(), вызываемая из основной программы, в свою очередь в этой функции происходит сканирование лексем из созданного лексическим анализатором файла и проверка их на правильность, основываясь на грамматике языка.
Всего используется 10 функций для анализа (на вход каждой подается массив из лексем и номер текущей лексемы):
int DECLAR(int mass[], int i) – проверка
правильности объявления
int MNOG(int mass[], int i) – проверка правильности написания идентификатора и константы, в первую очередь идет проверка на наличие множителя (в данном контексте под этим понимается любой записанный в таблице символов идентификатор или константа), если же записанный идентификатор имеет тип «unknow», то функция выдает ошибку на необъявленный идентификатор, т.е. в программе имеется неизвестная символьная конструкция. Для констант используется простая проверка на соответствие использованных при лексическом анализе констант и поступивших на вход синтаксического анализа, т.е. исключается появление новых, неизвестных чисел.
int SLAG(int mass[], int i) – проверка правильности слагаемого, т.е. конструкции вида “x*y/7*abc”. Сразу же учитывается возможность написания двух и более идентификаторов друг за другом (конструкции вида «a 1 b 105 c», заведомо неправильные, т.к. в них пропущены арифметические знаки), в этом случае также выдается соответствующая ошибка. Дальше происходит циклическая проверка, возвращающая истинное значение переменной res (она используется во всех функциях проверки) в том случае, если соблюдаются все условия синтаксиса языка: наличие множителя, за ним знака умножения, возведения в степень или деления, а следом – еще одного множителя и т.д. В случае нарушения этого условия выдается ошибка. Также имеется проверка на случай, если записано выражение вида “*у” или “**5”, то есть отсутствует первый множитель в слагаемом.
Информация о работе Разработка трехпроходного транслятора с исходного языка на язык ПЛ-1