Автор работы: Пользователь скрыл имя, 26 Мая 2013 в 02:23, курсовая работа
Мета роботи: вивчення складових частин, основних принципів побудови і функціонування компіляторів. Практичне освоєння методів побудови простих компіляторів для заданої вхідної мови.
Завдання:
Для програмної організації компілятора рекомендується використовувати Borland Delphi:
Компілятор повинен складатися:
лексичний аналізатор
синтаксичний аналізатор
оптимізатор
генератор результуючого кода
Компілятор виділяє закінчену синтаксичну конструкцію з тексту початкової програми, генерує для неї фрагмент результуючого коду і записує цей фрагмент в текст результуючої програми. Це повторюється для всіх синтаксичних конструкцій в програмі. Аналізуються такі синтаксичні конструкції як блоки операторів, описи процедур і функцій.
В лабораторній роботі результатом генерації коду є програма на мові асемблера. Взагалі є такі форми внутрішнього представлення програми:
В кожному конкретному компіляторі розробник вибирає одну з даних форм. В даній лабораторній роботі використовується 3 форма.
Тріада – запис операцій в формі з 3 складових: операція і 2 операнди.
<операція> (<операнд 1><операнд 2>)
Особливістю тріад є те, що один або обидва операнди можуть бути посиланнями на іншу тріаду в тому випадку, якщо в якості операнда даної тріади виступає результат іншої тріади, тому тріади послідовно нумерують для зручності вказання посилань одних тріад на інші (в реалізації компілятора можуть бути не номери, а вказівники). Тоді при зміні нумерації і порядка слідування не треба змінювати посилання.
Приклад: A := B*C + D - B*10
Тріади обчислюються послідовно одна за одною і результат обчислення зберігається в тимчасовій пам’яті.
Тріади дуже зручні для переведення їх кода в асемблер ний, але для тріад також потрібен алгоритм розподілу пам’яті для зберігання проміжних результатів обчислень, оскільки тимчасові змінні тріадами не використовуються (в цьому відмінність тріад від тетрад). Тріади не залежать від архітектури обчислювальної системи на яку орієнтована результуюча програма. Це машинно-незалежна форма внутрішнього представлення програми.
Переваги тріад:
вони наближені до двоадресних машинних команд, які найбільше поширені в наборах команд більшості комп’ютерів;
pr. |
end. |
; |
f |
( |
) |
else |
beg |
end |
rpt |
until |
a |
c |
:= |
or |
xor |
and |
< |
> |
= |
<> |
not |
- |
+ |
um |
! |
* |
/ | |
pr. |
|
= |
< |
< |
|
|
|
< |
|
< |
|
< |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
> |
|
|
; |
|
> |
> |
< |
|
|
|
< |
> |
< |
|
< |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if |
|
|
|
|
= |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
( |
|
|
|
< |
= |
|
|
|
|
|
< |
< |
|
< |
< |
< |
< |
< |
< |
< |
< |
< |
< |
< |
|
< |
< | |
) |
|
> |
> |
< |
|
> |
= |
< |
> |
< |
= |
< |
|
|
> |
> |
> |
> |
> |
> |
> |
|
> |
> |
|
|
> |
> |
else |
|
> |
> |
< |
|
|
> |
< |
> |
< |
|
< |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
beg. |
|
|
< |
< |
|
|
|
< |
= |
< |
|
< |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end |
|
> |
> |
|
|
|
> |
|
> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
repit |
|
|
|
|
= |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
until |
|
> |
> |
< |
|
|
> |
< |
< |
< |
|
< |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a |
|
> |
> |
|
|
> |
> |
|
> |
|
|
|
|
= |
> |
> |
> |
> |
> |
> |
> |
|
> |
> |
|
|
> |
> |
c |
|
> |
> |
|
|
> |
> |
|
> |
|
|
|
|
|
> |
> |
> |
> |
> |
> |
> |
|
> |
> |
|
|
> |
> |
:= |
|
> |
> |
|
< |
|
> |
|
> |
|
|
< |
< |
|
|
|
|
|
|
|
|
|
< |
< |
< |
|
< |
< |
or |
|
|
|
|
< |
> |
|
|
|
|
|
< |
< |
|
> |
> |
< |
< |
< |
< |
< |
< |
< |
< |
< |
|
< |
< |
xor |
|
|
|
|
< |
> |
|
|
|
|
|
< |
< |
|
> |
> |
< |
< |
< |
< |
< |
< |
< |
< |
< |
|
< |
< |
and |
|
|
|
|
< |
> |
|
|
|
|
|
< |
< |
|
> |
> |
> |
< |
< |
< |
< |
< |
< |
< |
< |
|
< |
< |
< |
|
|
|
|
< |
> |
|
|
|
|
|
< |
< |
|
> |
> |
> |
|
|
|
|
|
< |
< |
< |
|
< |
< |
> |
|
|
|
|
< |
> |
|
|
|
|
|
< |
< |
|
> |
> |
> |
|
|
|
|
|
< |
< |
< |
|
< |
< |
= |
|
|
|
|
< |
> |
|
|
|
|
|
< |
< |
|
> |
> |
> |
|
|
|
|
|
< |
< |
< |
|
< |
< |
<> |
|
|
|
|
< |
> |
|
|
|
|
|
< |
< |
|
> |
> |
> |
|
|
|
|
|
< |
< |
< |
|
< |
< |
not |
|
|
|
|
= |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- |
|
> |
> |
|
< |
> |
> |
|
> |
|
|
< |
< |
|
> |
> |
> |
> |
> |
> |
> |
|
> |
> |
< |
|
> |
> |
+ |
|
> |
> |
|
< |
> |
> |
|
> |
|
|
< |
< |
|
> |
> |
> |
> |
> |
> |
> |
|
> |
> |
< |
|
> |
> |
um |
|
> |
> |
|
< |
> |
> |
|
> |
|
|
< |
< |
|
> |
> |
> |
> |
> |
> |
> |
|
> |
> |
< |
|
> |
> |
! |
< |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* |
|
> |
> |
|
< |
> |
> |
|
> |
|
|
< |
< |
|
> |
> |
> |
> |
> |
> |
> |
|
> |
> |
< |
|
> |
> |
/ |
|
> |
> |
|
< |
> |
> |
|
> |
|
|
< |
< |
|
> |
> |
> |
> |
> |
> |
> |
|
> |
> |
< |
|
> |
> |
1. FormLab
unit FormLab4;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, ComCtrls, Grids, ExtCtrls,
LexElem, SyntSymb, Triads;
type
{ Типы возможных ошибок компилятора: файловая,
лексическая, синтаксическая, семантическая (триады)
или ошибок нет }
TErrType = (ERR_FILE, ERR_LEX, ERR_SYNT,
ERR_TRIAD, ERR_NO);
TCursovForm = class(TForm)
PageControl1: TPageControl;
SheetFile: TTabSheet;
SheetLexems: TTabSheet;
BtnExit: TButton;
GroupText: TGroupBox;
ListIdents: TMemo;
EditFile: TEdit;
BtnFile: TButton;
BtnLoad: TButton;
FileOpenDlg: TOpenDialog;
GridLex: TStringGrid;
SheetSynt: TTabSheet;
TreeSynt: TTreeView;
SheetTriad: TTabSheet;
GroupTriadAll: TGroupBox;
Splitter1: TSplitter;
GroupTriadSame: TGroupBox;
Splitter2: TSplitter;
GroupTriadConst: TGroupBox;
ListTriadAll: TMemo;
ListTriadConst: TMemo;
ListTriadSame: TMemo;
CheckDel_C: TCheckBox;
CheckDelSame: TCheckBox;
SheetAsm: TTabSheet;
ListAsm: TMemo;
CheckAsm: TCheckBox;
procedure BtnLoadClick(Sender: TObject);
procedure BtnFileClick(Sender: TObject);
procedure EditFileChange(Sender: TObject);
procedure BtnExitClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject;
var Action: TCloseAction);
private
{ Список лексем }
listLex: TLexList;
{ Синтаксический стек }
symbStack: TSymbStack;
{ Список триад }
listTriad: TTriadList;
{ Имена файлов: входного, результата и ошибок }
sInpFile,sOutFile,sErrFile: string;
{ Функция записи стартовых данных в файл ошибок }
procedure StartInfo(const sErrF: string);
{ Функция обработки командной строки }
procedure ProcessParams(
var flOptC,flOptSame,flOptAsm: Boolean);
{ Процедура инициализации таблицы
для отображения списка лексем }
procedure InitLexGrid;
{ Процедура отображения синтаксического дерева }
procedure MakeTree(nodeTree: TTreeNode;
symbSynt: TSymbol);
{ Процедура информации об ошибке }
procedure ErrInfo(const sErrF,sErr: string;
iPos,iLen: integer);
{ Функция запуска компилятора }
function CompRun(const sInF,sOutF,sErrF: string;
var symbRes: TSymbol;
flTrd,flDelC,flDelSame,flOptC,
flOptSame,flOptAsm: Boolean): TErrType;
public
{ Public declarations }
end;
var
CursovForm: TCursovForm;
implementation
{$R *.DFM}
uses FncTree, LexType, LexAuto, TrdType, TrdMake, TrdAsm,
TrdOpt;
procedure TCursovForm.InitLexGrid;
{ Процедура инициализации таблицы
для отображения списка лексем }
begin
with GridLex do
begin
RowCount := 2;
Cells[0,0] := '№ п/п';
Cells[1,0] := 'Лексема';
Cells[2,0] := 'Значение';
Cells[0,1] := '';
Cells[1,1] := '';
Cells[2,1] := '';
end;
end;
procedure TCursovForm.StartInfo(
const sErrF: string{имя файла ошибок});
{ Функция записи стартовых данных в файл ошибок }
var
i,iCnt: integer;{счетчик параметров и переменная цикла}
sTmp: string;{суммарная командная строка}
begin
{ Запоминаем имя файла ошибок }
sErrFile := sErrF;
{ Записываем в файл
ошибок дату запуска
ErrInfo(sErrFile,
Format('--- %s ---',[DateTimeToStr(Now)]),0,
{ Берем количество входных параметров }
iCnt := ParamCount;
{ Обнуляем суммарную командную строку }
sTmp := ParamStr(0);
{ Записываем в суммарную командную строку
все параметры последовательно }
for i:=1 to iCnt do
sTmp := sTmp +' '+ ParamStr(i);
{ Записываем в файл ошибок суммарную командную строку }
ErrInfo(sErrFile,sTmp,0,0);
end;
procedure TCursovForm.ProcessParams(
var flOptC,flOptSame,flOptAsm: Boolean{флаги});
{ Функция обработки командной строки }
var
i,iCnt,iLen: integer;
sTmp: string;
{ Список для записи ошибок параметров }
listErr: TStringList;
begin
{ Устанавливаем все флаги по умолчанию }
flOptC := True;
flOptSame := True;
flOptAsm := True;
{ Создаем список для записи ошибок параметров }
listErr := TStringList.Create;
try
{ Берем количество входных параметров }
iCnt := ParamCount;
{ Обрабатываем
все параметры, начиная со
for i:=2 to iCnt do
begin
{ Берем строку параметра }
sTmp := ParamStr(i);
{ Берем длину строки параметра }
iLen := Length(sTmp);
{ Если параметр слишком
со знака "-" - это неправильный параметр }
if (iLen < 3) or (sTmp[1] <> '-') then
{ Запоминаем ошибку в список }
listErr.Add(Format('Неверный параметр %d: "%s"!',
[i,sTmp]))
else
{ Иначе
обрабатываем параметр в
с его типом (второй символ) }
case sTmp[2] of
{ Флаг оптимизации ассемблера }
'a','A': flOptAsm := (sTmp[3] = '1');
{ Флаг оптимизации методом свертки }
'c','C': flOptC := (sTmp[3] = '1');
{ Флаг оптимизации исключением лишних операций }
's','S': flOptSame := (sTmp[3] = '1');
{ Имя выходного файла }
'o','O': sOutFile := System.Copy(sTmp,3,iLen-2);
{ Имя файла ошибок }
'e','E':
StartInfo(System.Copy(sTmp,3,
{ Параметр неизвестного типа }
else
{ Запоминаем ошибку в список }
listErr.Add(Format('Неверный параметр %d: "%s"!',
[i,sTmp]));
end{case};
end{for};
{ Ставим имена файлов по умолчанию,
если они не были указаны в параметрах }
if sOutFile = '' then
sOutFile := ChangeFileExt(sInpFile,'.asm')
if sErrFile = '' then
StartInfo(ChangeFileExt(
{ Берем количество ошибок в параметрах }
iCnt := listErr.Count-1;
{ Запоминаем информацию обо всех ошибках }
for i:=0 to iCnt do ErrInfo(sErrFile,listErr[i],0,
{ Освобождаем память, занятую списком ошибок }
finally listErr.Free;
end{try};
end;
procedure TCursovForm.FormCreate(Sender: TObject);
var
flOptC,flOptSame,flOptAsm: Boolean;
symbRes: TSymbol;
iErr: TErrType;
begin
symbRes := nil;
sOutFile := '';
sErrFile := '';
{ В начале
выполнения инициализируем
таблицу
идентификаторов,
и список триад }
InitTreeVar;
listLex := TLexList.Create;
symbStack := TSymbStack.Create;
listTriad := TTriadList.Create;
{ Если указан параметр - не надо открывать окно,
надо сразу запускать компилятор
и обрабатывать входной файл }
if ParamCount > 0 then
begin
{ Берем имя входного файла из первого параметра }
sInpFile := ParamStr(1);
{ Обрабатываем все остальные параметры }
ProcessParams(flOptC,
{ Запускаем компилятор }
iErr := CompRun(
sInpFile,sOutFile,sErrFile{
symbRes{ссылка на дерево разбора},
False{запоминать списки триад не надо},
flOptC{флаг удаления триад "C"},
flOptSame{флаг удаления триад "SAME"},
flOptC{флаг оптимизации по методу
свертки объектного кода },
flOptSame{флаг оптимизации исключ.
лишних операций},
flOptAsm{флаг оптимизации команд
ассемблера});
{ Если не было файловых ошибок,
то надо завершать работу }
if iErr <> ERR_FILE then Self.Close;
end;
end;
procedure TCursovForm.FormClose(Sender: TObject;
var Action: TCloseAction);
{ В конце
выполнения очищаем список
таблицу
идентификаторов,
и список триад }
begin
listTriad.Free;
symbStack.Free;
listLex.Free;
ClearTreeVar;
Application.Terminate;
end;
procedure TCursovForm.EditFileChange(
begin
{ Можно читать файл, только когда его имя не пустое }
BtnLoad.Enabled := (EditFile.Text <> '');
end;
procedure TCursovForm.BtnFileClick(
begin
if FileOpenDlg.Execute then
{ Выбор имени файла
с помощью стандартного
begin
EditFile.Text := FileOpenDlg.FileName;
BtnLoad.Enabled := (EditFile.Text <> '');
end;
end;
procedure TCursovForm.ErrInfo(const sErrF,sErr: string;
iPos,iLen: integer);
{ Процедура информации об ошибке }
var
{ Файл для записи информации об ошибке }
fileErr: TextFile;
begin
{ Если имя файла ошибок не пустое }
if sErrF <> '' then
try
{ Записываем информацию об ошибке в файл }
AssignFile(fileErr,sErrF);