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

Листинг П3.12. Создание списка триад на основе дерева разбора

Листинг П3.12. Создание списка триад на основе дерева разбора

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: Result:= symbOp[0].Lexem; { Если дочерний

символ построен по правилу № 27 или 28, то это лексема }

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;

Opers[1].OpType:= OP_CONST; {Заполняем операнды}

Opers[1].ConstVal:= 1; { для триады типа «JMP»,

которая должна быть в конце раздела «(B)E»}

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;

Opers[1].OpType:= OP_CONST; {Заполняем операнды}

Opers[1].ConstVal:= 1; { для триады типа «JMP»,

которая должна быть в конце раздела «doE» }

{ Второй операнд – ссылка на начало списка триад }

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;

Opers[2].OpType:= OP_CONST; {Второй операнд для}

Opers[2].ConstVal:= 0; { NOT не имеет значения }

{ Создаем триаду типа «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;

Opers[1].OpType:= OP_CONST; {Первый операнд для}

Opers[1].ConstVal:= 0; { унарной операции "-"

должен быть 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.

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


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