Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
35
Добавлен:
02.05.2014
Размер:
10 Кб
Скачать
unit TrdMake; {!!! Зависит от входного языка !!!}

interface
{ Модуль, обеспечивающий создание списка триад
  на основе структуры синтаксического разбора }

uses LexElem, Triads, SyntSymb;

function MakeTriadList(symbTop: TSymbol;
                       listTriad: TTriadList): TLexem;
{ Функция создания списка триад начиная  от корневого
  символа дерева  синтаксического разбора.
  Функция возвращает nil при успешном выполнении, иначе она
  возвращает ссылку на лексему, где произошла ошибка }

implementation

uses LexType, TrdType;

function GetLexem(symbOp: TSymbol): TLexem;
{ Функция, проверяющая является ли операнд лексемой }
begin
  case symbOp.Rule of
    { Если правил нет, это лексема! }
    0: Result := symbOp.Lexem;
    { Если дочерний символ построен по правилу №12,
      то это лексема }
    12: Result := symbOp[0].Lexem;
    { Если это арифметические скобки, надо проверить,
      не является ли лексемой операнд в скобках }
    13: Result := GetLexem(symbOp[1])
    { Иначе это не лексема }
    else Result := nil;
  end;
end;

function MakeTriadListNOP(symbTop: TSymbol;
                          listTriad: TTriadList): TLexem;
{ Функция создания списка триад начиная от корневого
  символа дерева синтаксического разбора
  (без добавления триады NOP в конец списка) }
var
  Opers: TOpArray; { массив операндов триад }
  iIns1,iIns2,iIns3: integer;
  { переменные для запоминания индексов триад в списке }
function MakeOperand(iOp{номер операнда},
  iSymOp{порядковый номер символа в синт. конструкции},
  iMin{минимальная позиция триады в списке},
  iSymErr: integer;
  {номер лексемы, на которой позиционировать ошибку}
  var iIns: integer{индекс триады в списке}): TLexem;
{ Функция формирования ссылки на операнд }
var lexTmp: TLexem;
begin
  { Проверяем, является ли операнд лексемой }
  lexTmp := GetLexem(symbTop[iSymOp]);
  if lexTmp <> nil then
  { Если да, то берем имя операнда в зависимости от типа }
  with lexTmp do
  begin
    if LexType = LEX_VAR then
    begin
      { Если это переменная, то запоминаем ссылку
        на таблицу идентификаторов }
      Opers[iOp].OpType  := OP_VAR;
      Opers[iOp].VarLink := VarInfo;
    end
    else
    if LexType = LEX_CONST then
    begin
      { Если это константа, то запоминаем её значение }
      Opers[iOp].OpType   := OP_CONST;
      Opers[iOp].ConstVal := ConstVal;
    end
    else
    begin
      { Иначе это ошибка, возвращаем лексему
        как указатель на место ошибки }
      Result := lexTmp;
      Exit;
    end;
    iIns := iMin;
    Result := nil;
  end
  else
  { иначе это синтаксическая конструкция }
  begin
    { Вызываем рекурсивно функцию создания списка триад }
    Result := MakeTriadListNOP(symbTop[iSymOp],listTriad);
    { Если произошла ошибка, прерываем выполнение }
    if Result <> nil then Exit;
    { Запоминаем индекс триады }
    iIns := listTriad.Count;
    { Если индекс меньше минимального (список не менялся) -
      это ошибка }
    if iIns <= iMin then
    begin
      Result := symbTop[iSymErr].Lexem;
      Exit;
    end;
    { Запоминаем ссылку на предыдущую триаду }
    Opers[iOp].OpType   := OP_LINK;
    Opers[iOp].TriadNum := iIns-1;
  end;
end;
function MakeOperation(
  Trd: TTriadType{тип создаваемой триады}): TLexem;
{ Функция создания списка триад для линейных операций }
begin
  { Создаем ссылку на первый операнд }
  Result := MakeOperand(1{op},0{sym},listTriad.Count,
                        1{sym err},iIns1);
  { Если произошла ошибка, прерываем выполнение }
  if Result <> nil then Exit;
  { Создаем ссылку на второй операнд }
  Result := MakeOperand(2{op},2{sym},iIns1,
                        1{sym err},iIns2);
  { Если произошла ошибка, прерываем выполнение }
  if Result <> nil then Exit;
  { Создаем саму триаду с двумя ссылками на операнды }
  listTriad.Add(TTriad.Create(Trd,Opers));
end;
begin
{ Тело главной функции. Начинаем с выбора типа правила }
  case symbTop.Rule of
    2,5:{'ifEthenEelseE'}
    { Полный условный оператор }
      begin
        { Запоминаем ссылку на первый операнд
          (условие "if") }
        Result := MakeOperand(1{op},1{sym},listTriad.Count,
                              0{sym err},iIns1);
        { Если произошла ошибка, прерываем выполнение }
        if Result <> nil then Exit;
        { Второй операнд - ссылка на триаду,
          номер которой пока не известен }
        Opers[2].OpType   := OP_LINK;
        Opers[2].TriadNum := 0;
        { Создаем триаду типа "IF" }
        listTriad.Add(TTriad.Create(TRD_IF,Opers));
        { Запоминаем ссылку на второй операнд
          (раздел "then") }
        Result := MakeOperand(2{op},3{sym},iIns1,
                              2{sym err},iIns2);
        { Если произошла ошибка, прерываем выполнение }
        if Result <> nil then Exit;
        { Заполняем операнды для триады типа "JMP", которая
          должна быть в конце раздела "then" }
        Opers[1].OpType   := OP_CONST;
        Opers[1].ConstVal := 1;
        { Второй операнд - ссылка на триаду, номер которой
          пока не известен }
        Opers[2].OpType   := OP_LINK;
        Opers[2].TriadNum := 0;
        { Создаем триаду типа "JMP" }
        listTriad.Add(TTriad.Create(TRD_JMP,Opers));
        { Для созданной ранее триады типа "IF" ставим
          ссылку в конец последовательности триад,
          созданной для раздела "then" }
        listTriad[iIns1].Links[2] := iIns2+1;
        { Запоминаем ссылку на третий операнд
          (раздел "else") }
        Result := MakeOperand(2{op},5{sym},iIns2,
                              4{sym err},iIns3);
        { Если произошла ошибка, прерываем выполнение }
        if Result <> nil then Exit;
        { Для созданной ранее триады типа "JMP" ставим
          ссылку в конец последовательности триад,
          созданной для раздела "else" }
        listTriad[iIns2].Links[2] := iIns3;
      end;
    3:{'ifEthenE'}
    { Неполный условный оператор }
      begin
        { Запоминаем ссылку на первый операнд
          (условие "if") }
        Result := MakeOperand(1{op},1{sym},listTriad.Count,
                              0{sym err},iIns1);
        { Если произошла ошибка, прерываем выполнение }
        if Result <> nil then Exit;
        { Второй операнд - ссылка на триаду,
          номер которой пока не известен }
        Opers[2].OpType   := OP_LINK;
        Opers[2].TriadNum := 0;
        { Создаем триаду типа "IF" }
        listTriad.Add(TTriad.Create(TRD_IF,Opers));
        { Запоминаем ссылку на второй операнд
          (раздел "then") }
        Result := MakeOperand(2{op},3{sym},iIns1,
                              2{sym err},iIns2);
        { Если произошла ошибка, прерываем выполнение }
        if Result <> nil then Exit;
        { Для созданной ранее триады типа "IF" ставим
          ссылку в конец последовательности триад,
          созданной для раздела "then" }
        listTriad[iIns1].Links[2] := iIns2;
      end;
    4,6:{'a:=E'}
    { Оператор присвоения }
      begin
        { Если первый операнд не является переменной,
          то это ошибка }
        if symbTop[0].Lexem.LexType <> LEX_VAR then
        begin
          Result := symbTop[0].Lexem;
          Exit;
        end;
        { Создаем ссылку на первый операнд - переменную }
        Opers[1].OpType := OP_VAR;
        Opers[1].VarLink := symbTop[0].Lexem.VarInfo;
        { Создаем ссылку на второй операнд }
        Result := MakeOperand(2{op},2{sym},listTriad.Count,
                              1{sym err},iIns1);
        { Если произошла ошибка, прерываем выполнение }
        if Result <> nil then Exit;
        { Создаем триаду типа "присвоение" }
        listTriad.Add(TTriad.Create(TRD_ASSIGN,Opers));
      end;
    { Генерация списка триад для линейных операций }
    7:{'EorE'}   Result := MakeOperation(TRD_OR);
    8:{'ExorE'}  Result := MakeOperation(TRD_XOR);
    10:{'EandE'} Result := MakeOperation(TRD_AND);
    { Для скобочного выражения нужно рекурсивно вызвать
      функцию для второго символа }
    13:{'(E)'}
       Result := MakeTriadListNOP(symbTop[1],listTriad);
    { Для лексем ничего не нужно делать }
    12: Result := nil;
    { Во всех остальных случаях нужно рекурсивно вызвать
      функцию для первого символа }
    else Result := MakeTriadListNOP(symbTop[0],listTriad);
  end{case Rule};
end;

function MakeTriadList(symbTop: TSymbol;
                       listTriad: TTriadList): TLexem;
{ Функция создания списка триад начиная от корневого
  символа дерева синтаксического разбора }
var
  i: integer;
  Opers: TOpArray;
  Trd: TTriad;
begin
  { Создаем список триад }
  Result := MakeTriadListNOP(symbTop,listTriad);
  { Если произошла ошибка, прерываем выполнение,
    иначе продолжаем... }
  if Result = nil then
  with listTriad do
  begin
    { Создаем пустую триаду "NOP" в конце списка }
    Opers[1].OpType   := OP_CONST;
    Opers[1].ConstVal := 0;
    Opers[2].OpType   := OP_CONST;
    Opers[2].ConstVal := 0;
    Add(TTriad.Create(TRD_NOP,Opers));
    { Для всех триад в списке расставляем флаг ссылки }
    for i:=Count-1 downto 0 do
    begin
      Trd := Triads[i];
      if Trd.TrdType in [TRD_IF,TRD_JMP] then
      begin
       { Если триада типа "переход" ("IF" или "JMP")
         и ссылается на другую триаду,
         то ту триаду надо пометить }
       if Trd.OpTypes[2] = OP_LINK then
         listTriad[Trd.Links[2]].IsLinked := True;
      end;
    end;
  end;
end;

end.

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