Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
31
Добавлен:
02.05.2014
Размер:
13.49 Кб
Скачать
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;
{ Если дочерний символ построен по правилу №27 или 28,
то это лексема }
27,28: Result := symbOp[0].Lexem;
{ Если это арифметические скобки, надо проверить,
не является ли лексемой операнд в скобках }
19,26: 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
if VarInfo.VarName = NAME_RESULT then
begin
{ Проверяем, что переменная имеет допустимое имя }
Result := lexTmp;
Exit;
end;
{ Если это переменная, то запоминаем ссылку
на таблицу идентификаторов }
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
5:{'if(B)EelseE'}
{ Полный условный оператор }
begin
{ Запоминаем ссылку на первый операнд
(условие "if(B)") }
Result := MakeOperand(1{op},2{sym},listTriad.Count,
1{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));
{ Запоминаем ссылку на второй операнд
(раздел "(B)E") }
Result := MakeOperand(2{op},4{sym},iIns1,
3{sym err},iIns2);
{ Если произошла ошибка, прерываем выполнение }
if Result <> nil then Exit;
{ Заполняем операнды для триады типа "JMP",
которая должна быть в конце раздела "(B)E" }
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" ставим
ссылку в конец последовательности триад,
созданной для раздела "(B)E" }
listTriad[iIns1].Links[2] := iIns2+1;
{ Запоминаем ссылку на третий операнд
(раздел "elseE") }
Result := MakeOperand(2{op},6{sym},iIns2,
5{sym err},iIns3);
{ Если произошла ошибка, прерываем выполнение }
if Result <> nil then Exit;
{ Для созданной ранее триады типа "JMP" ставим
ссылку в конец последовательности триад,
созданной для раздела "elseE" }
listTriad[iIns2].Links[2] := iIns3;
end;
6:{'if(B)E'}
{ Неполный условный оператор }
begin
{ Запоминаем ссылку на первый операнд
(условие "if(B)") }
Result := MakeOperand(1{op},2{sym},listTriad.Count,
1{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));
{ Запоминаем ссылку на второй операнд
(раздел "(B)E") }
Result := MakeOperand(2{op},4{sym},iIns1,
3{sym err},iIns2);
{ Если произошла ошибка, прерываем выполнение }
if Result <> nil then Exit;
{ Для созданной ранее триады типа "IF" ставим
ссылку в конец последовательности триад,
созданной для раздела "(B)E" }
listTriad[iIns1].Links[2] := iIns2;
end;
8:{'while(B)doE'}
{ Оператор цикла "while" }
begin
{ Запоминаем ссылку на первый операнд
(условие "while(B)") }
iIns3 := listTriad.Count;
Result := MakeOperand(1{op},2{sym},iIns3,
1{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));
{ Запоминаем ссылку на второй операнд
(раздел "doE") }
Result := MakeOperand(2{op},5{sym},iIns1,
4{sym err},iIns2);
{ Если произошла ошибка, прерываем выполнение }
if Result <> nil then Exit;
{ Заполняем операнды для триады типа "JMP", которая
должна быть в конце раздела "doE" }
Opers[1].OpType := OP_CONST;
Opers[1].ConstVal := 1;
{ Второй операнд - ссылка на начало созданного
списка триад }
Opers[2].OpType := OP_LINK;
Opers[2].TriadNum := iIns3;
{ Создаем триаду типа "JMP" }
listTriad.Add(TTriad.Create(TRD_JMP,Opers));
{ Для созданной ранее триады типа "IF" ставим
ссылку в конец последовательности триад,
созданной для раздела "doE" }
listTriad[iIns1].Links[2] := iIns2+1;
end;
9:{'a:=E'}
{ Оператор присвоения }
begin
{ Если первый операнд не является переменной,
то это ошибка }
if symbTop[0].Lexem.LexType <> LEX_VAR then
begin
Result := symbTop[0].Lexem;
Exit;
end;
{ Если имя первого операнда совпадает с именем
параметра, то это семантическая ошибка }
if (symbTop[0].Lexem.VarName = NAME_INPVAR)
or (symbTop[0].Lexem.VarName = NAME_RESULT) 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;
{ Генерация списка триад для линейных операций }
10:{'BorB'} Result := MakeOperation(TRD_OR);
11:{'BxorB'} Result := MakeOperation(TRD_XOR);
13:{'BandB'} Result := MakeOperation(TRD_AND);
15:{'E<E'} Result := MakeOperation(TRD_LT);
16:{'E>E'} Result := MakeOperation(TRD_GT);
17:{'E=E'} Result := MakeOperation(TRD_EQ);
18:{'E<>E'} Result := MakeOperation(TRD_NEQ);
21:{'E-E'} Result := MakeOperation(TRD_SUB);
22:{'E+E'} Result := MakeOperation(TRD_ADD);
20:{not(B)}
begin
{ Создаем ссылку на первый операнд }
Result := MakeOperand(1{op},2{sym},listTriad.Count,
1{sym err},iIns1);
{ Если произошла ошибка, прерываем выполнение }
if Result <> nil then Exit;
{ Второй операнд для унарной операции NOT
не имеет значения }
Opers[2].OpType := OP_CONST;
Opers[2].ConstVal := 0;
{ Создаем триаду типа "NOT" }
listTriad.Add(TTriad.Create(TRD_NOT,Opers));
end;
24:{uminE}
begin
{ Создаем ссылку на второй операнд }
Result := MakeOperand(2{op},1{sym},listTriad.Count,
0{sym err},iIns1);
{ Если произошла ошибка, прерываем выполнение }
if Result <> nil then Exit;
{ Первый операнд для унарной операции "-"
должен быть 0 }
Opers[1].OpType := OP_CONST;
Opers[1].ConstVal := 0;
{ Создаем триаду типа "UMIN" }
listTriad.Add(TTriad.Create(TRD_UMIN,Opers));
end;
{ Для логических, арифметических или операторных скобок
рекурсивно вызываем функцию для второго символа }
1,7,19,26:{'progEend.','beginEend','(E)','(B)'}
Result := MakeTriadListNOP(symbTop[1],listTriad);
{ Для списка операторов нужно рекурсивно вызвать
функцию два раза }
3:{E;E}
begin
Result := MakeTriadListNOP(symbTop[0],listTriad);
if Result <> nil then Exit;
Result := MakeTriadListNOP(symbTop[2],listTriad);
end;
{ Для лексем ничего делать не нужно }
27,28: 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.
Соседние файлы в папке Cursov