Автор работы: Пользователь скрыл имя, 08 Января 2014 в 21:12, курсовая работа
Компилятор – программный модуль, задачей которого является перевод программы, написанной на одном из языков программирования (исходный язык) в программу на язык ассемблера или язык машинных команд.
Целью данной курсовой работы являлось изучение составных частей, основных принципов построения и функционирования компиляторов, практическое освоение методов построения простейших компиляторов для заданного входного языка. Курсовая работа заключается в реализации отдельных фаз компиляции заданного языка.
Введение 3
1. Организация таблиц идентификаторов 4
1.2. Назначение таблиц идентификаторов 4
1.3. Метод рехеширования с использованием случайных чисел 4
1.4. Метод упорядоченного списка 8
1.5.Основные используемые функции 9
1.6. Результаты сравнения методов 14
2. Проектирование лексического анализатора 16
2.2. Принцип работы лексического анализатора 21
2.3. Схема распознавателя 21
2.4. Алгоритм лексического анализатора 25
2.5. Основные используемые функции 26
2.4. Результаты работы лексического анализатора 30
3. Проектирование синтаксического анализатора 32
3.2. Синтаксический анализатор 33
3.3. Грамматика простого предшествования 34
3.4. Грамматика операторного предшествования 35
3.5. Построение распознавателя для операторного предшествования 36
3.6. Основные используемые функции 37
3.7. Результаты работы синтаксического анализатора 39
Заключение 40
Список литературы 41
Дисциплина: Системное программное обеспечение
Курсовая работа
Тема: Создание компилятора
Содержание
Введение
1. Организация таблиц
1.2. Назначение таблиц
1.3. Метод рехеширования с
1.4. Метод упорядоченного списка
1.5.Основные используемые
1.6. Результаты сравнения методов
2. Проектирование лексического анализатора 16
2.2. Принцип работы лексического анализатора 21
2.3. Схема распознавателя 21
2.4. Алгоритм лексического
2.5. Основные используемые функции
2.4. Результаты работы
3. Проектирование синтаксического анализатора 32
3.2. Синтаксический анализатор
3.3. Грамматика простого
3.4. Грамматика операторного
3.5. Построение распознавателя
для операторного
3.6. Основные используемые функции 37
3.7. Результаты работы синтаксического анализатора 39
Заключение 40
Список литературы 41
Приложение А. Исходный текст программы 42
Приложение Б. Граф состояний лексического анализатора 54
Компилятор – программный модуль, задачей которого является перевод программы, написанной на одном из языков программирования (исходный язык) в программу на язык ассемблера или язык машинных команд.
Целью данной курсовой работы являлось изучение составных частей, основных принципов построения и функционирования компиляторов, практическое освоение методов построения простейших компиляторов для заданного входного языка.
Курсовая работа заключается в реализации отдельных фаз компиляции заданного языка.
В первой части работы
требуется разработать
Во второй части работы
требуется разработать
В третьей части работы
требуется разработать
В качестве среды разработки для реализации программы был использован Borland Delphi 7.
1. Организация таблицы идентификаторов
Задача компилятора заключается в том, чтобы хранить некоторую информацию, связанную с каждым элементом исходной программы, и иметь доступ к этой информации в течение всего процесса компиляции по имени элемента. Для решения этой задачи компилятор организует специальные хранилища данных, называемые таблицами идентификаторов. Состав информации хранимой для каждого элемента определяется семантикой входного языка и типом элемента.
Под идентификаторами подразумеваются константы, переменные, имена процедур и функций, формальные и фактические параметры.[1]
Метод организации таблиц идентификаторов,
основанный на использовании хеш-адресации,
заключается в помещении
Согласно этому методу, если для элемента A адрес h(A), вычисленный с помощью хеш-функции h, указывает на уже занятую ячейку, то необходимо
вычислить значение функции n1=h1(A) и проверить занятость ячейки по адресу n1. Если и она занята, то вычисляется значение h2(A) и так до тех пор, пока либо не будет найдена свободная ячейка, либо очередное значение hi(A) совпадет с h(A). В последнем случае считается, что таблица идентификаторов заполнена, и места в ней больше нет — выдается информация об ошибке размещения идентификатора в таблице.
Такую таблицу идентификаторов можно организовать по следующему алгоритму размещения элемента:
Шаг 1: Вычислить значение хеш-функции n = h(A) для нового элемента A.
Шаг 2: Если ячейка по адресу n пустая, то поместить в нее элемент A и завершить алгоритм, иначе i:=1 и перейти к шагу 3.
Шаг 3: Вычислить ni = hi(A). Если ячейка по адресу ni пустая, то поместить в нее элемент A и завершить алгоритм, иначе перейти к шагу 4.
Шаг 4: Если n = ni, то сообщить об ошибке и завершить алгоритм, иначе i:=i+1 и вернуться к шагу 3.
Тогда поиск элемента A в таблице идентификаторов, организованной таким образом, будет выполняться по следующему алгоритму:
Шаг 1: Вычислить значение хеш-функции n = h(A) для искомого элемента A.
Шаг 2: Если ячейка по адресу n пустая, то элемент не найден, алгоритм завершен, иначе сравнить имя элемента в ячейке n с именем искомого элемента A. Если они совпадают, то элемент найден и алгоритм завершен, иначе i:=1 и перейти к шагу 3.
Шаг 3: Вычислить ni = hi(A). Если ячейка по адресу ni пустая или n = ni, то элемент не найден и алгоритм завершен, иначе сравнить имя элемента в ячейке ni с именем искомого элемента A. Если они совпадают, то элемент найден и алгоритм завершен, иначе i:=i+1 и повторить шаг 3.
Схема алгоритма добавления идентификатора приведена на рис. 1.1.
Рис. 1. 1 Схема алгоритма добавления идентификатора
Схема алгоритма поиска идентификатора приведена на рис. 1.2.
Рис. 1.2. Схема алгоритма поиска идентификатора
Этот метод нельзя признать достаточно удачным, т.к. эффективность сильно зависит от заполненности таблицы идентификаторов и может возникнуть такая ситуация, когда не окажется ни одной свободной ячейки, адреса которых вычислены по заданной хэш-функции, тогда как в действительности в таблице идентификаторов полно пустых мест. 1.4. Метод упорядоченного списка
Этот метод является простым методом построения таблиц идентификаторов. Элементы записываются в таблицу в порядке возрастания. Так как упорядочивание таблицы идентификаторов происходит на всех этапах обращения к таблице, то для ее построения можно пользоваться только алгоритмом прямого упорядоченного включения элементов. При добавлении нового элемента в таблицу идентификаторов он сначала добавляется в конец таблицы, а затем идет переупорядочивание элементов таблицы идентификаторов. Эффективным методом для поиска элементов является логарифмический поиск, на каждом шаге которого, число элементов, которые могут содержать искомый элемент, сокращается в два раза. Максимально число сравнений при поиске 1+log2(N). [1]
Схема алгоритма добавления идентификатора представлена на рис. 1.3.
Рис. 1.3. Схема алгоритма добавления идентификатора
Схема алгоритма поиска идентификатора представлена на рис. 1.4.
Рис. 1.4. Схема алгоритма поиска идентификатора
Недостатком такого метода является требование упорядочивания таблицы идентификаторов на всех этапах обращения к этой таблице.
К положительным качествам метода можно отнести простоту его организации.
1.5. Основные используемые функции
Хеш-функция.
function HeshFunc(St:string):integer;
var dlina,sred:integer;
begin
dlina:=length(St);
if dlina=0 then Result:=0
else begin
sred:=(dlina+1)div 2;
if dlina=1 then Result:=ord(St[1])-64 else
if dlina=2 then
Result:=ord(St[1])+ord(St[
Result:=(ord(St[1])+ord(St[
end
end;
Заполнение
хэш-таблицы и таблицы
подсчет коллизий.
label Shag3;
var
S,Word:String;
NRow, i, Kol, u, KolO, Com, Key, Key1: Integer;
begin
{Рисование ХТ и занесение пустых значений во все ее ячейки}
KolO:=0;{Количество колизий}
Com:=0;{Количество сравнений}
u:=1;
with StringGrid1 do
begin
For NRow:=1 to 302 do
begin
cells[0,NRow]:=InttoStr(NRow+
cells[1,NRow]:=''
end
end;
{Собственно хэширование}
for i:=0 to Words.Count-1 do
begin
Kol:=0;
s:=Words[i];
key:=HeshFunc(s);
if StringGrid1.Cells[1,Key]='' then begin {ячейка с данным значением ХФ свободна}
Com:=Com+1;{число сравнений}
StringGrid1.Cells[1,Key]:=S;{
end
else {ячейка с данным заначением ХФ занята}
begin
Shag3: Kol:=Kol+1;
KolO:=KolO+1;
Com:=Com+1;
Key1:=((Key + Sl[u]) mod 302)+64;
if StringGrid1.Cells[1,Key1]='' then begin
{ячейка с данным значением ХФ свободна}
Com:=Com+1;{число сравнений}
StringGrid1.Cells[1,Key1]:=S;{
end
else {ячейка с данным заначением ХФ занята}
if Key1=Key then begin
ShowMessage('Ошибка! В ХТ нет свободного места');
Exit
end
else begin
key:=key1;
u:=u+1;
goto Shag3;
end
end;
end;
Word:=InttoStr(KolO);
Form1.Memo2.Lines.Add('ПРИ ДОБАВЛЕНИИ ВСЕХ ЭЛЕМЕНТОВ:');
Form1.Memo2.Lines.Add('
word:=InttoSTR(Com);
Form1.Memo2.Lines.Add('
end;
Поиск в таблице идентификаторов.
var j,i,t,k,a,b,m,n:integer;s1:
label 1,2,3,4,5;
begin
k:=0; t:=memo1.Lines.Count; s1:=Edit1.text;
for j:=1 to t do
if StringGrid2.Cells[1,j]<>'' then k:=k+1;
if s1='' then
begin
MessageDlg('Поле ввода пусто', mtInformation,[mbOk],0);
goto 3;
end;
a:=1; b:=k; i:=0;
1: if ((a+b) div 2)=0 then m:=(a+b) div 2 else m:=(a+b) div 2;
i:=i+1;
if s1=StringGrid2.Cells[1,m] then
begin
MessageDlg('Элемент найден', mtInformation,[mbOk],0);
n:=m; goto 2;
end
else
if s1<StringGrid2.Cells[1,m] then
begin
b:=m;
if a=b-1 then
begin
i:=i+1;
if s1=StringGrid2.Cells[1,a] then
begin
MessageDlg('Элемент найден', mtInformation,[mbOk],0);
n:=a; goto 2;
end
else
begin
MessageDlg('Элемент не найден', mtInformation,[mbOk],0); goto 3;
end;
end
else goto 1;
end
else
begin
a:=m;
if a=b then
begin
i:=i+1;
if s1=StringGrid2.Cells[1,b] then
begin
MessageDlg('Элемент найден', mtInformation,[mbOk],0);
n:=b; goto 3;
end
else
begin
MessageDlg('Элемент не найден', mtInformation,[mbOk],0); goto 3;
end;
end
else goto 1;
end;
2:
Memo3.Lines.Add('ПРИ ПОИСКЕ');
Memo3.Lines.Add('Количество
Memo3.Lines.Add('Номер ID = '+IntToStr(n)); goto 4;
3:
Memo3.Lines.Add('ПРИ ПОИСКЕ');
Memo3.Lines.Add('Количество сравнений '+IntToStr(i));
Memo3.Lines.Add('
4:
end;
1.6. Результаты сравнения методов
Поиск в таблице идентификаторов выпо
На рис. 1.5 представлена экранная форма метода рехеширования с использованием случайных чисел и упорядоченного списка.
Рис. 1.5. Экранная форма
организации таблицы
В данном случае при наличии во входном файле двенадцати идентификаторов количество требуемых сравнений для заполнения таблицы идентификаторов методом рехеширования с использованием случайных чисел оказалось меньше, чем методом упорядоченного списка (методом рехеширования с использованием случайных чисел количество сравнений равно 15, а методом упорядоченного списка количество сравнений равно 50).
Следовательно, и время для организации
таблицы идентификаторов
Экранная форма поиска существующего идентификатора представлена на рис. 1.8.
Рис. 1.8. Экранная форма поиска существующего идентификатора