Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
35
Добавлен:
02.05.2014
Размер:
9 Кб
Скачать
unit FormLab4;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls, ComCtrls, Grids, ExtCtrls,
  LexElem, SyntSymb, Triads;

type
  TLab4Form = 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;
    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;
    { Процедура инициализации таблицы
      для отображения списка лексем }
    procedure InitLexGrid;
    { Процедура отображения синтаксического дерева }
    procedure MakeTree(nodeTree: TTreeNode;
                       symbSynt: TSymbol);
   public
    { Public declarations }
  end;

var
  Lab4Form: TLab4Form;

implementation

{$R *.DFM}

uses FncTree, LexType, LexAuto, TrdType, TrdMake, TrdOpt;

procedure TLab4Form.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 TLab4Form.FormCreate(Sender: TObject);
{ В начале выполнения инициализируем список лесем,
  таблицу идентификаторов, синтаксический стек
  и список триад }
begin
  InitTreeVar;
  listLex := TLexList.Create;
  symbStack := TSymbStack.Create;
  listTriad := TTriadList.Create;
end;

procedure TLab4Form.FormClose(Sender: TObject;
                          var Action: TCloseAction);
{ В конце выполнения очищаем список лесем,
  таблицу идентификаторов, синтаксический стек
  и список триад }
begin
  listTriad.Free;
  symbStack.Free;
  listLex.Free;
  ClearTreeVar
end;

procedure TLab4Form.EditFileChange(Sender: TObject);
begin
  { Можно читать файл, только когда его имя не пустое }
  BtnLoad.Enabled := (EditFile.Text <> '');
end;

procedure TLab4Form.BtnFileClick(Sender: TObject);
begin
  if FileOpenDlg.Execute then
  { Выбор имени файла с помощью стандартного диалога }
  begin
    EditFile.Text := FileOpenDlg.FileName;
    BtnLoad.Enabled := (EditFile.Text <> '');
  end;
end;

procedure TLab4Form.BtnLoadClick(Sender: TObject);
{ Процедура чтения и анализа файла }
var
  i,iCnt,iErr: integer;
  symbRes: TSymbol;
  nodeTree: TTreeNode;
  lexTmp: TLexem;
begin
  { Очищаем список лексем }
  listLex.Clear;
  { Очищаем синтаксический стек }
  symbStack.Clear;
  { Очищаем список триад }
  listTriad.Clear;
  { Очищаем таблицу отображения списка лексем
    и синтаксическое дерево }
  InitLexGrid;
  TreeSynt.Items.Clear;
  try
    { Чтение файла в список строк }
    ListIdents.Lines.LoadFromFile(EditFile.Text);
    except
      MessageDlg('Ошибка чтения файла!',mtError,[mbOk],0);
      Exit;
  end;
  { Анализ списка строк и заполнение списка лексем }
  iErr := MakeLexList(ListIdents.Lines,listLex);
  if iErr <> 0 then
  { Если анализ не успешный, выводим сообщение об ошибке }
  begin
    MessageDlg(Format('Неверная лексема "%s" в строке %d!',
                      [listLex[0].LexInfoStr,iErr]),
               mtWarning,[mbOk],0);
    { Берем позицию ошибочной лексемы из фиктивной лексемы
      в начале списка и позиционируем на нее список строк }
    ListIdents.SelStart := listLex[0].PosAll;
    ListIdents.SelLength := listLex[0].PosNum;
    { Отображаем позицию ошибки в списке строк }
    ListIdents.SetFocus;
  end
  else
  { Если анализ успешный,
    отображаем список лексем в таблице }
  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;
    { Добавляем в конец списка лексем информационную
      лексему "конец строки" }
    with ListIdents do
     listLex.Add(TLexem.CreateInfo('Конец строки',
                          Length(Text),Lines.Count-1,0));
    { Строим дерево синтаксического разбора и
      получаем ссылку на его корень }
    symbRes := BuildSyntList(listLex,symbStack);
    { Если эта ссылка содержит лексические данные,
      значит была ошибка в месте, указанном лексемой }
    if symbRes.SymbType = SYMB_LEX then
    begin
      MessageDlg(
              Format('Синтаксическая ошибка в строке %d!',
                     [symbRes.Lexem.StrNum+1]),
              mtWarning,[mbOk],0);
      { Берем позицию ошибочной лексемы по ссылке
        и позиционируем на нее список строк }
      ListIdents.SelStart := symbRes.Lexem.PosAll;
      ListIdents.SetFocus;
      { Освобождаем ссылку на лексему }
      symbRes.Free;
    end
    else
    { Если не было синтаксической ошибки,
      заполняем дерево синтаксического разбора }
    begin
      { Записываем данные в корень дерева }
      nodeTree := TreeSynt.Items.Add(nil,
                                     symbRes.SymbolStr);
      { Строим остальные элементы дерева от его корня }
      MakeTree(nodeTree,symbRes);
      { Раскрываем всё дерево }
      nodeTree.Expand(True);
      { Позиционируем указатель на корневой элемент }
      TreeSynt.Selected := nodeTree;
      { Строим список триад по синтаксическому дереву }
      lexTmp := MakeTriadList(symbRes,listTriad);
      { Если есть ссылка на лексему, значит была
        семантическая ошибка }
      if lexTmp <> nil then
      begin
        MessageDlg(
               Format('Семантическая ошибка в строке %d!',
                      [lexTmp.StrNum+1]),
               mtWarning,[mbOk],0);
        { Берем позицию ошибочной лексемы по ссылке
          и позиционируем на нее список строк }
        ListIdents.SelStart := lexTmp.PosAll;
        ListIdents.SetFocus;
      end
      else
      { Если есть ссылка пуста, значит триады построены }
      begin
        { Сохраняем общий список триад }
        listTriad.WriteToList(ListTriadAll.Lines);
        { Выполняем оптимизацию методом
          свертки объектного кода }
        OptimizeConst(listTriad);
        { Если указан флаг, удаляем триады типа "C" }
        if CheckDel_C.Checked then
          DelTriadTypes(listTriad,TRD_CONST);
        { Сохраняем общий список после оптимизации }
        listTriad.WriteToList(ListTriadConst.Lines);
        { Выполняем оптимизацию методом
          исключения лишних операций }
        OptimizeSame(listTriad);
        { Если указан флаг, удаляем триады типа "SAME" }
        if CheckDelSame.Checked then
          DelTriadTypes(listTriad,TRD_SAME);
        { Сохраняем общий список после оптимизации }
        listTriad.WriteToList(ListTriadSame.Lines);
      end;
    end;
  end;
end;

procedure TLab4Form.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 TLab4Form.BtnExitClick(Sender: TObject);
{ Завершение работы с программой }
begin
  Self.Close;
end;

end.
Соседние файлы в папке Labs