Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
15
Добавлен:
02.05.2014
Размер:
9.69 Кб
Скачать
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