Книга: Системное программное обеспечение. Лабораторный практикум

Листинг П3.14. Реализация пользовательского интерфейса

Листинг П3.14. Реализация пользовательского интерфейса

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;

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;{счетчик параметров и переменная цикла}

sT: string;{суммарная командная строка}

begin

sErrFile:= sErrF; { Запоминаем имя файла ошибок }

{ Записываем в файл ошибок дату запуска компилятора }

ErrInfo(sErrFile,

Format(– %s —,[DateTimeToStr(Now)]),0,0);

iCnt:= ParamCount; { Количество входных параметров }

sT:= ParamStr(0); { Обнуляем командную строку }

{Записываем в командную строку параметры последовательно}

for i:=1 to iCnt do sT:= sT + + ParamStr(i);

{ Записываем в файл ошибок суммарную командную строку }

ErrInfo(sErrFile,sT,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,iLen-2));

else { Параметр неизвестного типа }

{ Запоминаем ошибку в список }

listErr.Add(Format('Неверный параметр %d: «%s»!

[i,sTmp]));

end{case};

end{for};

{ Ставим имена файлов по умолчанию,

если они не были указаны в параметрах }

if sOutFile = then

sOutFile:= ChangeFileExt(sInpFile, asm');

if sErrFile = then

StartInfo(ChangeFileExt(sInpFile, err'));

iCnt:= listErr.Count-1; { Количество ошибок }

{ Запоминаем информацию обо всех ошибках }

for i:=0 to iCnt do ErrInfo(sErrFile,listErr[i],0,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,flOptSame,flOptAsm);

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(Sender: TObject);

begin { Можно читать файл, только когда его имя не пустое }

BtnLoad.Enabled:= (EditFile.Text <> );

end;

procedure TCursovForm.BtnFileClick(Sender: TObject);

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);

if FileExists(sErrF) then Append(fileErr)

else Rewrite(fileErr);

writeln(fileErr,sErr);

CloseFile(fileErr); { и закрываем его }

except { Если ошибка записи в файл, сообщаем об этом }

MessageDlg(Format('Ошибка записи в файл «%s»! #13#10

+ 'Ошибка компиляции: %s![sErrF,sErr]),

mtError,[mbOk],0);

end { Если имя файла ошибок пустое, }

else { выводим информацию на экран }

begin { Позиционируем список строк на место ошибки }

ListIdents.SelStart:= iPos;

ListIdents.SelLength:= iLen;

MessageDlg(sErr,mtWarning,[mbOk],0);{Выводим сообщение}

ListIdents.SetFocus; { Выделяем ошибку в списке строк }

end;

end;

function TCursovForm.CompRun({Функция запуска компилятора}

const sInF,{имя входного файла}

sOutF,{имя результирующего файла}

sErrF{имя файла ошибок}:string;

var symbRes: TSymbol;{корень дерева разбора}

flTrd,{флаг записи триад в списки}

flDelC,{флаг удаления триад типа "C"}

flDelSame,{флаг удаления триад типа «SAME»}

flOptC,{флаг оптимизации методом свертки}

flOptSame,{флаг исключения лишних операций}

flOptAsm{флаг оптимизации ассемблерного кода}

: Boolean): TErrType;

var i,iCnt,iErr: integer; { переменные счетчиков }

lexTmp: TLexem; { временная лексема для инф. об ошибках }

sVars,sAdd: string; { временные строки }

asmList: TStringList; { список ассемблерных команд }

begin{ Очищаем список лексем, синтаксический стек и список триад }

listLex.Clear; symbStack.Clear; listTriad.Clear;

try { Чтение файла в список строк }

ListIdents.Lines.LoadFromFile(sInF);

except { Если файловая ошибка – сообщаем об этом }

Result:= ERR_FILE;

MessageDlg('Ошибка чтения файла!mtError,[mbOk],0);

Exit; { Дальнейшая работа компилятора невозможна }

end; { Анализ списка строк и заполнение списка лексем }

iErr:= MakeLexList(ListIdents.Lines,listLex);

if iErr<>0 then {Анализ неуспешный – сообщаем об ошибке}

begin { Берем позицию ошибки из лексемы в начале списка }

ErrInfo(sErrF,

Format('Неверная лексема «%s» в строке %d!

[listLex[0].LexInfoStr,iErr]),

listLex[0].PosAll,listLex[0].PosNum);

Result:= ERR_LEX; { Результат – лексическая ошибка }

end

else { Добавляем в конец списка лексем }

begin { информационную лексему «конец строки» }

with ListIdents do

listLex.Add(TLexem.CreateInfo('Конец строки',

Length(Text), Lines.Count-1,0));

{ Выполняем синтаксический разбор

и получаем ссылку на корень дерева разбора }

symbRes:= BuildSyntList(listLex,symbStack);

{ Если эта ссылка содержит лексические данные,

значит, была ошибка в месте, указанном лексемой }

if symbRes.SymbType = SYMB_LEX then

begin { Берем позицию ошибки из лексемы по ссылке }

ErrInfo(sErrF,

Format('Синтаксическая ошибка в строке %d поз. %d!

[symbRes.Lexem.StrNum+1,symbRes.Lexem.PosNum]),

symbRes.Lexem.PosAll,0);

symbRes.Free; { Освобождаем ссылку на лексему }

symbRes:= nil;

Result:= ERR_SYNT; { Это синтаксическая ошибка }

end

else { Иначе – ссылка указывает на корень

синтаксического дерева }

begin { Строим список триад по синтаксическому дереву }

lexTmp:= MakeTriadList(symbRes,listTriad);

{ Если есть ссылка на лексему, значит, была

семантическая ошибка }

if lexTmp <> nil then

begin { Берем позицию ошибочной лексемы по ссылке }

ErrInfo(sErrF,

Format('Семантическая ошибка в строке %d поз. %d!

[lexTmp.StrNum+1,lexTmp.PosNum]),

lexTmp.PosAll,0);

Result:= ERR_TRIAD; { Это семантическая ошибка }

end

else { Если ссылка пуста, значит, триады построены }

begin

Result:= ERR_NO; { Результат – «ошибок нет» }

{ Если указан флаг, сохраняем общий список триад }

if flTrd then

listTriad.WriteToList(ListTriadAll.Lines);

if flOptC then { Если указан флаг, выполняем }

begin { оптимизацию путем свертки объектного кода }

OptimizeConst(listTriad);

{ Если указан флаг, удаляем триады типа «C» }

if flDelC then

DelTriadTypes(listTriad,TRD_CONST);

end; { Если указан флаг,}

if flTrd then {сохраняем триады после оптимизации}

listTriad.WriteToList(ListTriadConst.Lines);

if flOptSame then { Если указан флаг, выполняем

begin{оптимизацию путем исключения лишних операций}

OptimizeSame(listTriad);

{ Если указан флаг, удаляем триады типа «SAME» }

if flDelSame then

DelTriadTypes(listTriad,TRD_SAME);

end; { Если указан флаг,}

if flTrd then {сохраняем триады после оптимизации}

listTriad.WriteToList(ListTriadSame.Lines);

{ Распределяем регистры по списку триад }

iCnt:= MakeRegisters(listTriad);

{ Создаем и записываем список ассемблерных команд }

asmList:= TStringList.Create;

try

with asmList do

begin

Clear; { Очищаем список ассемблерных команд }

{ Пишем заголовок программы }

Add(Format('program %s;,[NAME_PROG]));

{ Запоминаем перечень всех идентификаторов }

sVars:= IdentList(, ,NAME_INPVAR,NAME_FUNCT);

if sVars <> then

begin{Если перечень идентификаторов не пустой,}

Add( ); { записываем его с указанием }

Add('var'); { типа данных }

Add(Format(%s: %s;,[sVars,NAME_TYPE]));

end;

Add( );

{ Пишем заголовок функции }

Add(Format('function %0:s(%1:s: %2:s): %2:s;

+ stdcall;,

[NAME_FUNCT,NAME_INPVAR,NAME_TYPE]));

if iCnt > 0 then {Если регистров для хранения}

begin {промежуточных результатов не хватило}

Add('var'); {и нужны временные переменные,}

sVars:= ; {то заполняем их список.}

for i:=0 to iCnt do

begin

sAdd:= Format(%s%d',[TEMP_VARNAME,i]);

if sVars = then sVars:= sAdd

else sVars:= sVars +, + sAdd;

end;

Add(Format(%s: %s;,[sVars,NAME_TYPE]));

end;

Add('begin'); { В тело функции записываем }

Add(asm'); { список команд ассемблера, }

Add(#9'pushad'#9#9 {запоминаем регистры,});

MakeAsmCode(listTriad,asmList,flOptAsm);

Add(#9'popad'#9#9 {восстанавливаем регистры,});

Add(end;);

Add('end;);

Add( ); { Описываем одну входную переменную }

Add(Format('var %s: %s;,

[NAME_INPVAR,NAME_TYPE]));

Add( );

Add('begin'); { Заполняем главную программу }

Add(Format(readln(%s);,[NAME_INPVAR]));

Add(Format(writeln(%s(%s));,

[NAME_FUNCT,NAME_INPVAR]));

Add(readln;);

Add('end.);

end{with}; {Если установлен флаг, записываем}

if flTrd then {команды для отображения на экране}

ListAsm.Lines.AddStrings(asmList);

if sOutF <> then { Если есть имя рез. файла,}

try { записываем туда список всех команд }

asmList.SaveToFile(sOutF);

except Result:= ERR_FILE;

end;

finally asmList.Free; {Уничтожаем список команд}

end{try}; {после его отображения и записи в файл}

end;

end;

end;

end;

procedure TCursovForm.BtnLoadClick(Sender: TObject);

{ Процедура чтения и анализа файла }

var i,iCnt: integer; { переменные счетчиков }

iRes: TErrType; { переменная для хранения результата }

symbRes: TSymbol; { временная переменная корня дерева}

nodeTree: TTreeNode; { переменная для узлов дерева }

begin

symbRes:= nil; { Корень дерева разбора вначале пустой }

InitLexGrid; {Очищаем таблицу отображения списка лексем}

TreeSynt.Items.Clear; { Очищаем синтаксическое дерево }

iRes:= CompRun({ Вызываем функцию компиляции }

EditFile.Text, , ,{задан только входной файл}

symbRes{указатель на дерево разбора},

True{Списки триад нужно запоминать},

CheckDel_C.Checked {флаг удаления триад "C"},

CheckDelSame.Checked {флаг удаления триад «SAME»},

True {флаг оптимизации «свертка объектного кода»},

True {флаг оптимизации исключения лишних операций},

CheckAsm.Checked {оптимизация команд ассемблера});

if iRes > ERR_LEX then {Если не было лексической ошибки,}

begin { заполняем список лексем }

GridLex.RowCount:= listLex.Count+1; { Количество строк }

iCnt:= listLex.Count-1;

for i:=0 to iCnt do

begin { Цикл по всем прочитанным лексемам }

{ Первая колонка – номер }

GridLex.Cells[0,i+1]:= IntToStr(i+1);

{ Вторая колонка – тип лексемы }

GridLex.Cells[1,i+1]:=

LexTypeName(listLex[i].LexType);

{ Третья колонка – значение лексемы }

GridLex.Cells[2,i+1]:= listLex[i].LexInfoStr;

end;

end;

if (iRes > ERR_SYNT) and (symbRes <> nil) then

{ Если не было синтаксической ошибки,}

begin { заполняем дерево синтаксического разбора }

{ Записываем данные в корень дерева }

nodeTree:= TreeSynt.Items.Add(nil,symbRes.SymbolStr);

MakeTree(nodeTree,symbRes); { Строим дерево от корня }

nodeTree.Expand(True); { Раскрываем все дерево }

{ Позиционируем указатель на корневой элемент }

TreeSynt.Selected:= nodeTree;

end;

if iRes > ERR_TRIAD then { Если не было семантической }

begin { ошибки, то компиляция успешно завершена }

MessageDlg('Компиляция успешно выполнена!

mtInformation,[mbOk],0);

PageControl1.ActivePageIndex:= 4;

end;

end;

procedure TCursovForm.MakeTree(

{ Процедура отображения синтаксического дерева }

nodeTree: TTreeNode; {ссылка на корневой элемент

отображаемой части дерева на экране}

symbSynt: TSymbol {ссылка на синтаксический символ,

связанный с корневым элементом этой части дерева});

var i,iCnt: integer; { переменные счетчиков }

nodeTmp: TTreeNode; { текущий узел дерева }

begin { Берем количество дочерних вершин для текущей }

iCnt:= symbSynt.Count-1;

for i:=0 to iCnt do

begin { Цикл по всем дочерним вершинам }

{ Добавляем к дереву на экране вершину

и запоминаем ссылку на нее }

nodeTmp:= TreeSynt.Items.AddChild(nodeTree,

symbSynt[i].SymbolStr);

{ Если эта вершина связана с нетерминальным символом,

рекурсивно вызываем процедуру построения дерева }

if symbSynt[i].SymbType = SYMB_SYNT then

MakeTree(nodeTmp,symbSynt[i]);

end;

end;

procedure TCursovForm.BtnExitClick(Sender: TObject);

{ Завершение работы с программой }

begin

Self.Close;

end;

end.

Оглавление книги


Генерация: 1.528. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз