Створення компілятора

Вивчення складових частин, основних принципів побудови і функціонування компіляторів. Поняття хешування, сутність алгоритму роботи лексичного аналізатора. Практичне освоєння методів побудови простих компіляторів для заданої вхідної мови - Borland Delphi.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык украинский
Дата добавления 27.05.2013
Размер файла 763,6 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

constructor CreateKey(LexKey: TLexType;

iA,iSt,iP: integer);

constructor CreateVar(VarInf: TVarInfo;

iA,iSt,iP: integer);

constructor CreateConst(iVal: integer;

iA,iSt,iP: integer);

constructor CreateInfo(sInf: string;

iA,iSt,iP: integer);

destructor Destroy; override;

{ Свойства для получения информации о лексеме }

property LexType: TLexType read LexInfo.LexType;

property VarInfo: TVarInfo read LexInfo.VarInfo;

property ConstVal: integer read LexInfo.ConstVal;

{ Свойства для чтения позиции лексемы

в исходном тексте программы }

property StrNum: integer read iStr;

property PosNum: integer read iPos;

property PosAll: integer read iAllP;

{ Текстовая информация о типе лексемы }

function LexInfoStr: string;

{ Имя для лексемы-переменной }

function VarName: string;

end;

{ Структура для описания списка лексем }

TLexList = class(TList)

public

{ Деструктор для освобождения памяти

при уничтожении списка }

destructor Destroy; override;

{ Процедура очистки списка }

procedure Clear; override;

{ Процедура и свойство для получения информации

о лексеме по ее номеру }

function GetLexem(iIdx: integer): TLexem;

property Lexem[iIdx: integer]: TLexem read GetLexem;

default;

end;

implementation

uses SysUtils, LexAuto;

onstructor TLexem.CreateKey(LexKey: TLexType;

iA,iSt,iP: integer);

{ Конструктор создания лексемы типа "ключевое слово" }

begin

inherited Create;

LexInfo.LexType := LexKey;

{ запоминаем тип ключевого слова }

iStr := iSt; { запоминаем позицию лексемы }

iPos := iP;

iAllP := iA;

end;

constructor TLexem.CreateVar(VarInf: TVarInfo;

iA,iSt,iP: integer);

{ Конструктор создания лексемы типа "ключевое слово" }

begin

inherited Create;

LexInfo.LexType := LEX_VAR; { тип - "переменная" }

{ запоминаем ссылку на таблицу идентификаторов }

LexInfo.VarInfo := VarInf;

iStr := iSt; { запоминаем позицию лексемы }

iPos := iP;

iAllP := iA;

end;

constructor TLexem.CreateConst(iVal: integer;

iA,iSt,iP: integer);

{ Конструктор создания лексемы типа "константа" }

begin

inherited Create;

LexInfo.LexType := LEX_CONST; { тип - "константа" }

{ запоминаем значение константы }

LexInfo.ConstVal := iVal;

iStr := iSt; { запоминаем позицию лексемы }

iPos := iP;

iAllP := iA;

end;

constructor TLexem.CreateInfo(sInf: string;

iA,iSt,iP: integer);

{ Конструктор создания информационной лексемы }

begin

inherited Create;

LexInfo.LexType := LEX_START; { тип - "доп. лексема" }

{ выделяем память для информации }

LexInfo.szInfo := StrAlloc(Length(sInf)+1);

{ запоминаем информацию }

StrPCopy(LexInfo.szInfo,sInf);

iStr := iSt; { запоминаем позицию лексемы }

iPos := iP;

iAllP := iA;

end;

destructor TLexem.Destroy;

begin

{ Освобождаем занятую память,

если это информационная лексема }

if LexType = LEX_START then StrDispose(LexInfo.szInfo);

inherited Destroy;

end;

function TLexem.VarName: string;

{ Функция получения имени лексемы типа "переменная" }

begin

Result := VarInfo.VarName;

end;

function TLexem.LexInfoStr: string;

{ Текстовая информация о типе лексемы }

begin

case LexType of

LEX_VAR: Result := VarName;

{ для переменной - ее имя }

LEX_CONST: Result := IntToStr(ConstVal);

{ для константы - значение }

LEX_START: Result := StrPas(LexInfo.szInfo);

{ для инф. лексемы - информация }

else Result := LexTypeInfo(LexType);

{ для остальных - имя типа }

end;

end;

procedure TLexList.Clear;

{ Процедура очистки списка }

var i: integer;

begin

{ Уничтожаем все элементы списка }

for i:=Count-1 downto 0 do Lexem[i].Free;

inherited Clear; { вызываем функцию базового класса }

end;

destructor TLexList.Destroy;

{ Деструктор для освобождения памяти

при уничтожении списка }

begin

Clear; { Уничтожаем все элементы списка }

{ Вызываем деструктор базового класса }

inherited Destroy;

end;

function TLexList.GetLexem(iIdx: integer): TLexem;

{ Получение лексемы из списка по ее номеру }

begin

Result := TLexem(Items[iIdx]);

end;

end.

5. LexAuto

unit LexAuto; {!!! Зависит от входного языка !!!}

interface

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

по исходному тексту программы }

uses Classes, TblElem, LexType, LexElem;

{ Функция создания списка лексем по исходному

тексту программы }

function MakeLexList(listFile: TStrings;

listLex: TLexList): integer;

implementation

uses SysUtils, FncTree;

type

{ Перечень всех возможных состояний конечного автомата }

TAutoPos = (

AP_START,AP_IF1,AP_IF2,AP_NOT1,AP_NOT2,AP_NOT3,

AP_ELSE1,AP_ELSE2,AP_ELSE3,AP_ELSE4,AP_END2,AP_END3,

AP_PROG1,AP_PROG2,AP_PROG3,AP_PROG4,AP_OR1,AP_OR2,

AP_BEGIN1,AP_BEGIN2,AP_BEGIN3,AP_BEGIN4,AP_BEGIN5,

AP_XOR1,AP_XOR2,AP_XOR3,

AP_AND1,AP_AND2,AP_AND3,

AP_REPEAT1,AP_REPEAT2,AP_REPEAT3,AP_REPEAT4,AP_REPEAT5,

AP_COMM,AP_COMMSG,AP_ASSIGN,AP_VAR,AP_CONST,

AP_UNTIL1,AP_UNTIL2,AP_SIGN,AP_LT,AP_FIN,AP_ERR);

function MakeLexList(listFile: TStrings;

listLex: TLexList): integer;

{ Функция создания списка лексем по исходному

тексту программы }

var

i,j,iCnt,iStr, { Переменные и счетчики циклов }

iAll,{ Счетчик общего количества входных символов }

{ Переменные для запоминания позиции начала лексемы }

iStComm,iStart: integer;

posCur: TAutoPos;{ Текущее состояние конечного автомата }

{ Строки для временного хранения результатов }

sCurStr,sTmp: string;

{ Несколько простых процедур для работы со списком лексем }

procedure AddVarToList(posNext: TAutoPos; iP: integer);

{ Процедура добавления переменной в список }

begin

{ Выделяем имя переменной из текущей строки }

sTmp := System.Copy(sCurStr,iStart,iP-iStart);

{ При создании переменной она сначала заносится

в таблицу идентификаторов, а потом ссылка на нее -

в таблицу лексем }

listLex.Add(TLexem.CreateVar(AddTreeVar(sTmp),

iStComm,i,iStart));

iStart := j;

iStComm := iAll-1;

posCur := posNext;

end;

procedure AddVarKeyToList(keyAdd: TLexType;

posNext: TAutoPos);

{ Процедура добавления переменной и

разделителя в список }

begin

{ Выделяем имя переменной из текущей строки }

sTmp := System.Copy(sCurStr,iStart,j-iStart);

{ При создании переменной она сначала заносится

в таблицу идентификаторов, а потом ссылка на нее -

в таблицу лексем }

listLex.Add(TLexem.CreateVar(AddTreeVar(sTmp),

iStComm,i,iStart));

{ Добавляем разделитель после переменной }

listLex.Add(TLexem.CreateKey(keyAdd,iAll,i,j));

iStart := j;

iStComm := iAll-1;

posCur := posNext;

end;

function StrBinToInt(S : string) : integer;

var

ii, li, mi : integer;

begin

li:=length(S);

if li>8 then begin

posCur := AP_ERR;

li:=8;

end;

mi:=1;

Result:=0;

for ii := li downto 1 do begin

case S[ii] of

'0':;

'1': Result:=Result+mi;

else begin

Result:=0;

posCur := AP_ERR;

Exit;

end;

end;

mi:=mi*2;

end;

end;

procedure AddConstToList(posNext: TAutoPos; iP: integer);

{ Процедура добавления константы в список }

begin

{ Выделяем константу из текущей строки }

sTmp := System.Copy(sCurStr,iStart,iP-iStart);

{ Заносим константу в список вместе с ее значением }

listLex.Add(TLexem.CreateConst(StrBinToInt(sTmp),

iStComm,i,iStart));

iStart := j;

iStComm := iAll-1;

if posCur<>AP_ERR then

posCur := posNext;

end;

procedure AddConstKeyToList(keyAdd: TLexType;

posNext: TAutoPos);

{ Процедура добавления константы и разделителя в список }

begin

{ Выделяем константу из текущей строки }

sTmp := System.Copy(sCurStr,iStart,j-iStart);

{ Заносим константу в список вместе с ее значением }

listLex.Add(TLexem.CreateConst(StrBinToInt(sTmp),iStComm,

i,iStart));

{ Добавляем разделитель после константы }

listLex.Add(TLexem.CreateKey(keyAdd,iAll,i,j));

iStart := j;

iStComm := iAll-1;

if posCur<>AP_ERR then

posCur := posNext;

end;

procedure AddKeyToList(keyAdd: TLexType;

posNext: TAutoPos);

{ Процедура добавления ключевого слова или

разделителя в список }

begin

listLex.Add(TLexem.CreateKey(keyAdd,iStComm,i,iStart));

iStart := j;

iStComm := iAll-1;

posCur := posNext;

end;

procedure Add2KeysToList(keyAdd1,keyAdd2: TLexType;

posNext: TAutoPos);

{ Процедура добавления ключевого слова и

разделителя в список }

begin

listLex.Add(TLexem.CreateKey(keyAdd1,iStComm,i,iStart));

listLex.Add(TLexem.CreateKey(keyAdd2,iAll,i,j));

iStart := j;

iStComm := iAll-1;

posCur := posNext;

end;

procedure KeyLetter(chNext: char; posNext: TAutoPos);

{ Процедура проверки очередного символа ключевого слова }

begin

case sCurStr[j] of

':': AddVarToList(AP_ASSIGN,j);

'-': AddVarKeyToList(LEX_SUB,AP_SIGN);

'+': AddVarKeyToList(LEX_ADD,AP_SIGN);

'*': AddKeyToList(LEX_MUL,AP_SIGN);

'/': AddKeyToList(LEX_DIV,AP_SIGN);

'=': AddVarKeyToList(LEX_EQ,AP_SIGN);

'>': AddKeyToList(LEX_GT,AP_SIGN);

'<': AddVarToList(AP_LT,j);

'(': AddKeyToList(LEX_OPEN,AP_SIGN);

')': AddKeyToList(LEX_CLOSE,AP_START);

'{': posCur := AP_COMMSG;

';': AddVarKeyToList(LEX_SEMI,AP_START);

' ',#10,#13,#9: AddVarToList(AP_START,j);

else

if sCurStr[j] = chNext then posCur := posNext

else

if sCurStr[j] in ['0'..'9','A'..'Z','a'..'z','_']

then posCur := AP_VAR

else posCur := AP_ERR;

end{case list};

end;

procedure KeyFinish(keyAdd: TLexType);

{ Процедура проверки завершения ключевого слова }

begin

case sCurStr[j] of

'-': Add2KeysToList(keyAdd,LEX_UMIN,AP_SIGN);

'+': Add2KeysToList(keyAdd,LEX_ADD,AP_SIGN);

'*': AddKeyToList(LEX_MUL,AP_SIGN);

'/': AddKeyToList(LEX_DIV,AP_SIGN);

'=': Add2KeysToList(keyAdd,LEX_EQ,AP_SIGN);

'>': Add2KeysToList(keyAdd,LEX_GT,AP_SIGN);

'<': AddKeyToList(keyAdd,AP_LT);

'(': AddKeyToList(LEX_OPEN,AP_SIGN);

')': AddKeyToList(LEX_CLOSE,AP_START);

'{': posCur := AP_COMMSG;

';': Add2KeysToList(keyAdd,LEX_SEMI,AP_START);

'0'..'9','A'..'Z','a'..'z','_': posCur := AP_VAR;

' ',#10,#13,#9: AddKeyToList(keyAdd,AP_SIGN);

else posCur := AP_ERR;

end{case list};

end;

begin

{ Обнуляем общий счетчик символов и результат функции }

iAll := 0;

Result := 0;

iStComm := 0;

{ Устанавливаем начальное состояние конечного автомата }

posCur := AP_START;

{ Цикл по всем строкам входного файла }

iCnt := listFile.Count-1;

for i:=0 to iCnt do

begin

{ Позиция начала лексемы - первый символ }

iStart := 1;

{ Запоминаем текущую строку }

sCurStr := listFile[i];

{ Цикл по всем символам текущей строки }

iStr := Length(sCurStr);

j:=0;

repeat

Inc(j);

{ Увеличиваем общий счетчик символов }

Inc(iAll);

{ Моделируем работу конечного автомата в зависимости

от состояния КА и текущего символа входной строки }

case posCur of

AP_START:

begin

{ В начальном состоянии запоминаем позицию

начала лексемы }

iStart := j;

iStComm := iAll-1;

case sCurStr[j] of

'b': posCur := AP_BEGIN1;

'i': posCur := AP_IF1;

'p': posCur := AP_PROG1;

'e': posCur := AP_ELSE1;

'r': posCur := AP_REPEAT1;

'u': posCur := AP_UNTIL1;

'o': posCur := AP_OR1;

'x': posCur := AP_XOR1;

's': posCur := AP_SHL1;

'a': posCur := AP_AND1;

'n': posCur := AP_NOT1;

':': posCur := AP_ASSIGN;

'-': AddKeyToList(LEX_SUB,AP_SIGN);

'+': AddKeyToList(LEX_ADD,AP_SIGN);

'*': AddKeyToList(LEX_MUL,AP_SIGN);

'/': AddKeyToList(LEX_DIV,AP_SIGN);

'=': AddKeyToList(LEX_EQ,AP_SIGN);

'>': AddKeyToList(LEX_GT,AP_SIGN);

'<': posCur := AP_LT;

'(': AddKeyToList(LEX_OPEN,AP_SIGN);

')': AddKeyToList(LEX_CLOSE,AP_START);

'{': posCur := AP_COMMSG;

';': AddKeyToList(LEX_SEMI,AP_START);

'0'..'9': posCur := AP_CONST;

'A'..'Z','c','f'..'h','j'..'m',

'q'..'r','t'..'v','y','z','_': posCur := AP_VAR;

' ',#10,#13,#9: ;

else posCur := AP_ERR;

end{case list};

end;

AP_SIGN:

begin

{ Состояние, когда может встретиться

унарный минус }

iStart := j;

iStComm := iAll-1;

case sCurStr[j] of

'b': posCur := AP_BEGIN1;

'i': posCur := AP_IF1;

'p': posCur := AP_PROG1;

'e': posCur := AP_ELSE1;

'w': posCur := AP_REPEAT1;

'd': posCur := AP_UNTIL1;

'o': posCur := AP_OR1;

'x': posCur := AP_XOR1;

's': posCur := AP_SHL1;

'a': posCur := AP_AND1;

'n': posCur := AP_NOT1;

'-': AddKeyToList(LEX_UMIN,AP_SIGN);

'(': AddKeyToList(LEX_OPEN,AP_SIGN);

')': AddKeyToList(LEX_CLOSE,AP_START);

'{': posCur := AP_COMMSG;

'0'..'9': posCur := AP_CONST;

'A'..'Z','c','f'..'h','j'..'m',

'q'..'r','t'..'v','y','z','_': posCur := AP_VAR;

' ',#10,#13,#9: ;

else posCur := AP_ERR;

end{case list};

end;

AP_LT:

{ Знак меньше или знак неравенства? }

case sCurStr[j] of

'b': AddKeyToList(LEX_LT,AP_BEGIN1);

'i': AddKeyToList(LEX_LT,AP_IF1);

'p': AddKeyToList(LEX_LT,AP_PROG1);

'e': AddKeyToList(LEX_LT,AP_ELSE1);

'r': AddKeyToList(LEX_LT,AP_REPEAT1);

'u': AddKeyToList(LEX_LT,AP_UNTIL1);

'o': AddKeyToList(LEX_LT,AP_OR1);

'x': AddKeyToList(LEX_LT,AP_XOR1);

's': AddKeyToList(LEX_LT,AP_SHL1);

'a': AddKeyToList(LEX_LT,AP_AND1);

'n': AddKeyToList(LEX_LT,AP_NOT1);

'>': AddKeyToList(LEX_NEQ,AP_SIGN);

'-': Add2KeysToList(LEX_LT,LEX_UMIN,AP_SIGN);

'(': Add2KeysToList(LEX_LT,LEX_OPEN,AP_SIGN);

'0'..'9': AddKeyToList(LEX_LT,AP_CONST);

'A'..'Z','c','f'..'h','j'..'m','q'..'r','t'..'v',

'y','z','_': AddKeyToList(LEX_LT,AP_VAR);

' ',#10,#13,#9: AddKeyToList(LEX_LT,AP_SIGN);

else posCur := AP_ERR;

end{case list};

AP_ELSE1:

{ "else", или же "end", или переменная? }

case sCurStr[j] of

'l': posCur := AP_ELSE2;

'n': posCur := AP_END2;

':': AddVarToList(AP_ASSIGN,j);

'-': AddVarKeyToList(LEX_SUB,AP_SIGN);

'+': AddVarKeyToList(LEX_ADD,AP_SIGN);

'*': AddKeyToList(LEX_MUL,AP_SIGN);

'/': AddKeyToList(LEX_DIV,AP_SIGN);

'=': AddVarKeyToList(LEX_EQ,AP_SIGN);

'>': AddKeyToList(LEX_GT,AP_SIGN);

'<': AddVarToList(AP_LT,j);

'(': AddKeyToList(LEX_OPEN,AP_SIGN);

')': AddKeyToList(LEX_CLOSE,AP_START);

'{': posCur := AP_COMMSG;

';': AddVarKeyToList(LEX_SEMI,AP_START);

'0'..'9','A'..'Z','a'..'k','m',

'o'..'z','_': posCur := AP_VAR;

' ',#10,#13,#9: AddVarToList(AP_START,j);

else posCur := AP_ERR;

end{case list};

AP_IF1: KeyLetter('f',AP_IF2);

AP_IF2: KeyFinish(LEX_IF);

AP_ELSE2: KeyLetter('s',AP_ELSE3);

AP_ELSE3: KeyLetter('e',AP_ELSE4);

AP_ELSE4: KeyFinish(LEX_ELSE);

AP_OR1: KeyLetter('r',AP_OR2);

AP_OR2: KeyFinish(LEX_OR);

AP_UNTIL1: KeyLetter('o',AP_UNTIL2);

AP_UNTIL2: KeyFinish(LEX_UNTIL);

AP_XOR1: KeyLetter('o',AP_XOR2);

AP_XOR2: KeyLetter('r',AP_XOR3);

AP_XOR3: KeyFinish(LEX_XOR);

AP_AND1: KeyLetter('n',AP_AND2);

AP_AND2: KeyLetter('d',AP_AND3);

AP_AND3: KeyFinish(LEX_AND);

AP_NOT1: KeyLetter('o',AP_NOT2);

AP_NOT2: KeyLetter('t',AP_NOT3);

AP_NOT3: KeyFinish(LEX_NOT);

AP_PROG1: KeyLetter('r',AP_PROG2);

AP_PROG2: KeyLetter('o',AP_PROG3);

AP_PROG3: KeyLetter('g',AP_PROG4);

AP_PROG4: KeyFinish(LEX_PROG);

AP_REPEAT1: KeyLetter('h',AP_REPEAT2);

AP_REPEAT2: KeyLetter('i',AP_REPEAT3);

AP_REPEAT3: KeyLetter('l',AP_REPEAT4);

AP_REPEAT4: KeyLetter('e',AP_REPEAT5);

AP_REPEAT5: KeyFinish(LEX_REPEAT);

AP_BEGIN1: KeyLetter('e',AP_BEGIN2);

AP_BEGIN2: KeyLetter('g',AP_BEGIN3);

AP_BEGIN3: KeyLetter('i',AP_BEGIN4);

AP_BEGIN4: KeyLetter('n',AP_BEGIN5);

AP_BEGIN5: KeyFinish(LEX_BEGIN);

AP_END2: KeyLetter('d',AP_END3);

AP_END3:

{ "end", или же "end.", или переменная? }

case sCurStr[j] of

'-': Add2KeysToList(LEX_END,LEX_UMIN,AP_SIGN);

'+': Add2KeysToList(LEX_END,LEX_ADD,AP_SIGN);

'*': AddKeyToList(LEX_MUL,AP_SIGN);

'/': AddKeyToList(LEX_DIV,AP_SIGN);

'=': Add2KeysToList(LEX_END,LEX_EQ,AP_SIGN);

'>': Add2KeysToList(LEX_END,LEX_GT,AP_SIGN);

'<': AddKeyToList(LEX_END,AP_LT);

'(': AddKeyToList(LEX_OPEN,AP_SIGN);

')': AddKeyToList(LEX_CLOSE,AP_START);

'{': posCur := AP_COMMSG;

';': Add2KeysToList(LEX_END,LEX_SEMI,AP_START);

'.': AddKeyToList(LEX_FIN,AP_START);

'0'..'9','A'..'Z','a'..'z','_':

posCur := AP_VAR;

' ',#10,#13,#9: AddKeyToList(LEX_END,AP_SIGN);

else posCur := AP_ERR;

end{case list};

AP_ASSIGN:

case sCurStr[j] of

'=': AddKeyToList(LEX_ASSIGN,AP_SIGN);

else posCur := AP_ERR;

end{case list};

AP_VAR:

case sCurStr[j] of

':': AddVarToList(AP_ASSIGN,j);

'-': AddVarKeyToList(LEX_SUB,AP_SIGN);

'+': AddVarKeyToList(LEX_ADD,AP_SIGN);

'*': AddKeyToList(LEX_MUL,AP_SIGN);

'/': AddKeyToList(LEX_DIV,AP_SIGN);

'=': AddVarKeyToList(LEX_EQ,AP_SIGN);

'>': AddVarKeyToList(LEX_GT,AP_SIGN);

'<': AddVarToList(AP_LT,j);

'(': AddKeyToList(LEX_OPEN,AP_SIGN);

')': AddKeyToList(LEX_CLOSE,AP_START);

'\': posCur := AP_COMMSG;

';': AddVarKeyToList(LEX_SEMI,AP_START);

'0'..'9','A'..'Z','a'..'z','_':

posCur := AP_VAR;

'^': AddVarToList(AP_COMM,j);

' ',#10,#13,#9: AddVarToList(AP_START,j);

else posCur := AP_ERR;

end{case list};

AP_CONST:

case sCurStr[j] of

':': AddConstToList(AP_ASSIGN,j);

'-': AddConstKeyToList(LEX_SUB,AP_SIGN);

'+': AddConstKeyToList(LEX_ADD,AP_SIGN);

'*': AddKeyToList(LEX_MUL,AP_SIGN);

'/': AddKeyToList(LEX_DIV,AP_SIGN);

'=': AddConstKeyToList(LEX_EQ,AP_SIGN);

'>': AddConstKeyToList(LEX_GT,AP_SIGN);

'<': AddConstToList(AP_LT,j);

'(': AddKeyToList(LEX_OPEN,AP_SIGN);

')': AddKeyToList(LEX_CLOSE,AP_START);

'}': posCur := AP_COMMSG;

';': AddConstKeyToList(LEX_SEMI,AP_START);

'0'..'9': posCur := AP_CONST;

' ',#10,#13,#9: AddConstToList(AP_START,j);

else posCur := AP_ERR;

end{case list};

AP_COMM:

case sCurStr[j] of

'\': if (j<iStr)and(sCurStr[j+1]=')') then begin

posCur := AP_START;

Inc(j);

Inc(iAll);

end;

end{case list};

AP_COMMSG:

case sCurStr[j] of

'}': if (j<iStr)and(sCurStr[j+1]=')') then begin

posCur := AP_SIGN;

Inc(j);

Inc(iAll);

end;

end{case list};

end{case pos};

{ Проверяем, не достигнут ли конец строки }

if j = iStr then

begin

{ Конец строки - это конец текущей лексемы }

case posCur of

AP_IF2: AddKeyToList(LEX_IF,AP_SIGN);

AP_PROG4: AddKeyToList(LEX_PROG,AP_START);

AP_ELSE4: AddKeyToList(LEX_ELSE,AP_START);

AP_BEGIN5: AddKeyToList(LEX_BEGIN,AP_START);

AP_REPEAT5: AddKeyToList(LEX_REPEAT,AP_SIGN);

AP_END3: AddKeyToList(LEX_END,AP_START);

AP_OR2: AddKeyToList(LEX_OR,AP_SIGN);

AP_UNTIL2: AddKeyToList(LEX_UNTIL,AP_SIGN);

AP_XOR3: AddKeyToList(LEX_XOR,AP_SIGN);

AP_AND3: AddKeyToList(LEX_AND,AP_SIGN);

AP_NOT3: AddKeyToList(LEX_AND,AP_SIGN);

AP_LT: AddKeyToList(LEX_LT,AP_SIGN);

AP_FIN: AddKeyToList(LEX_FIN,AP_START);

AP_CONST: AddConstToList(AP_START,j+1);

AP_ASSIGN: posCur := AP_ERR;

AP_IF1,AP_PROG1,AP_PROG2,AP_PROG3,

AP_ELSE1,AP_ELSE2,AP_ELSE3,AP_XOR1,AP_XOR2,

AP_OR1,AP_UNTIL1,AP_AND1,AP_AND2,AP_NOT1,AP_NOT2,

AP_REPEAT1,AP_REPEAT2,AP_REPEAT3,AP_REPEAT4,

AP_END2,AP_BEGIN1,AP_BEGIN2,AP_BEGIN3,AP_BEGIN4,

AP_VAR: AddVarToList(AP_START,j+1);

end{case pos2};

end;

{ Проверяем не была ли ошибка в лексемах }

if posCur = AP_ERR then

begin

{ Если была ошибка, вычисляем позицию

ошибочной лексемы }

iStart := (j - iStart)+1;

{ и запоминаем ее в виде фиктивной лексемы в начале

списка для детальной диагностики ошибки }

listLex.Insert(0,

TLexem.CreateInfo('Недопустимая лексема',

iAll-iStart,i,iStart));

{ Если ошибка, прерываем цикл }

Break;

end;

do j=iStr;

{ В конце строки увеличиваем общий счетчик символов

на 2: конец строки и возврат каретки }

Inc(iAll,2);

{ Если ошибка, запоминаем номер ошибочной строки

и прерываем цикл }

if posCur = AP_ERR then

begin

Result := i+1;

Break;

end;

end;

{ Если комментарий не был закрыт, то это ошибка }

if posCur in [AP_COMM,AP_COMMSG] then

begin

listLex.Insert(0,

TLexem.CreateInfo('Незакрытый комментарий',

iStComm,iCnt,iAll-iStComm));

Result := iCnt;

end

else

if not (posCur in [AP_START,AP_SIGN,AP_ERR]) then

{ Если КА не в начальном состоянии -

это неверная лексема }

begin

listLex.Insert(0,

TLexem.CreateInfo('Незавершенная лексема',

iAll-iStart,iCnt,iStart));

Result := iCnt;

end;

end;

end.

6. LexType

unit LexType; {!!! Зависит от входного языка !!!}

interface

{ Модуль, содержащий описание всех типов лексем }

type

{ Возможные типы лексем в программе }

TLexType =

(LEX_PROG, LEX_FIN, LEX_SEMI, LEX_IF, LEX_OPEN, LEX_CLOSE,

LEX_ELSE, LEX_BEGIN, LEX_END, LEX_REPEAT, LEX_UNTIL, LEX_VAR,

LEX_CONST, LEX_ASSIGN, LEX_OR, LEX_XOR, LEX_AND,

LEX_LT, LEX_GT, LEX_EQ, LEX_NEQ, LEX_NOT,

LEX_SUB, LEX_ADD,LEX_MUL,LEX_DIV, LEX_UMIN, LEX_START);

{ Функция получения строки наименования типа лексемы }

function LexTypeName(lexT: TLexType): string;

{ Функция получения текстовой информации о типе лексемы }

function LexTypeInfo(lexT: TLexType): string;

implementation

function LexTypeName(lexT: TLexType): string;

{ Функция получения строки наименования типа лексемы }

begin

case lexT of

LEX_OPEN: Result := 'Открывающая скобка';

LEX_CLOSE: Result := 'Закрывающая скобка';

LEX_ASSIGN: Result := 'Знак присвоения';

LEX_VAR: Result := 'Переменная';

LEX_CONST: Result := 'Константа';

LEX_SEMI: Result := 'Разделитель';

LEX_ADD,LEX_SUB,LEX_MUL,LEX_DIV,LEX_UMIN,LEX_GT,LEX_LT,LEX_EQ,

LEX_NEQ: Result := 'Знак операции';

else Result := 'Ключевое слово';

end;

end;

function LexTypeInfo(lexT: TLexType): string;

{ Функция получения текстовой информации о типе лексемы }

begin

case lexT of

LEX_PROG: Result := 'prog';

LEX_FIN: Result := 'end.';

LEX_SEMI: Result := ';';

LEX_IF: Result := 'if';

LEX_OPEN: Result := '(';

LEX_CLOSE: Result := ')';

LEX_ELSE: Result := 'else';

LEX_BEGIN: Result := 'begin';

LEX_END: Result := 'end';

LEX_REPEAT: Result := 'repeat';

LEX_UNTIL: Result := 'until';

LEX_VAR: Result := 'a';

LEX_CONST: Result := 'c';

LEX_ASSIGN: Result := ':=';

LEX_OR: Result := 'or';

LEX_XOR: Result := 'xor';

LEX_AND: Result := 'and';

LEX_LT: Result := '<';

LEX_GT: Result := '>';

LEX_EQ: Result := '=';

LEX_NEQ: Result := '<>';

LEX_NOT: Result := 'not';

LEX_ADD: Result := '+';

LEX_MUL: Result := '*';

LEX_DIV: Result := '/';

LEX_SUB,

LEX_UMIN: Result := '-';

else Result := '';

end;

end;

end.

7. SyntRyle

unit SyntRule; {!!! Зависит от входного языка !!!}

interface

{ Модуль, содержащий описание матрицы предшествования и правил грамматики }

uses LexType, Classes;

const

RULE_LENGTH = 7; { максимальная длина правила

(в расчете на символы грамматики) }

RULE_NUM = 30; { общее количество правил грамматики }

var

{ Матрица операторного предшествования }

GramMatrix: array[TLexType,TLexType] of char =

( {pr. end. ; if ( ) else beg end rpt until a c := or xor and < > = <> not - + um ! * /}

{pr.} (' ','=','<','<',' ',' ',' ','<',' ','<',' ','<',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '),

{end.}(' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','>',' ',' '),

{;} (' ','>','>','<',' ',' ',' ','<','>','<',' ','<',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '),

{if} (' ',' ',' ',' ','=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '),

{(} (' ',' ',' ',' ','<','=',' ',' ',' ',' ',' ','<','<',' ','<','<','<','<','<','<','<','<','<','<','<',' ','<','<'),

{)} (' ','>','>','<',' ','>','=','<','>','<','=','<',' ',' ','>','>','>','>','>','>','>',' ','>','>',' ',' ','>','>'),

{else}(' ','>','>','<',' ',' ','>','<','>','<',' ','<',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '),

{beg.}(' ',' ','<','<',' ',' ',' ','<','=','<',' ','<',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '),

{end} (' ','>','>',' ',' ',' ','>',' ','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '),

{repeat}(' ',' ',' ',' ','=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '),

{until} (' ','>','>','<',' ',' ','>','<','<','<',' ','<',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '),

{a} (' ','>','>',' ',' ','>','>',' ','>',' ',' ',' ',' ','=','>','>','>','>','>','>','>',' ','>','>',' ',' ','>','>'),

{c} (' ','>','>',' ',' ','>','>',' ','>',' ',' ',' ',' ',' ','>','>','>','>','>','>','>',' ','>','>',' ',' ','>','>'),

{:=} (' ','>','>',' ','<',' ','>',' ','>',' ',' ','<','<',' ',' ',' ',' ',' ',' ',' ',' ',' ','<','<','<',' ','<','<'),

{or} (' ',' ',' ',' ','<','>',' ',' ',' ',' ',' ','<','<',' ','>','>','<','<','<','<','<','<','<','<','<',' ','<','<'),

{xor} (' ',' ',' ',' ','<','>',' ',' ',' ',' ',' ','<','<',' ','>','>','<','<','<','<','<','<','<','<','<',' ','<','<'),

{and} (' ',' ',' ',' ','<','>',' ',' ',' ',' ',' ','<','<',' ','>','>','>','<','<','<','<','<','<','<','<',' ','<','<'),

{<} (' ',' ',' ',' ','<','>',' ',' ',' ',' ',' ','<','<',' ','>','>','>',' ',' ',' ',' ',' ','<','<','<',' ','<','<'),

{>} (' ',' ',' ',' ','<','>',' ',' ',' ',' ',' ','<','<',' ','>','>','>',' ',' ',' ',' ',' ','<','<','<',' ','<','<'),

{=} (' ',' ',' ',' ','<','>',' ',' ',' ',' ',' ','<','<',' ','>','>','>',' ',' ',' ',' ',' ','<','<','<',' ','<','<'),

{<>} (' ',' ',' ',' ','<','>',' ',' ',' ',' ',' ','<','<',' ','>','>','>',' ',' ',' ',' ',' ','<','<','<',' ','<','<'),

{not} (' ',' ',' ',' ','=',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '),

{-} (' ','>','>',' ','<','>','>',' ','>',' ',' ','<','<',' ','>','>','>','>','>','>','>',' ','>','>','<',' ','<','<'),

{+} (' ','>','>',' ','<','>','>',' ','>',' ',' ','<','<',' ','>','>','>','>','>','>','>',' ','>','>','<',' ','<','<'),

{um} (' ','>','>',' ','<','>','>',' ','>',' ',' ','<','<',' ','>','>','>','>','>','>','>',' ','>','>','<',' ','>','>'),

{!} ('<',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '),

{*} (' ','>','>',' ','<','>','>',' ','>',' ',' ','<','<',' ','>','>','>','>','>','>','>',' ','>','>','<',' ','<','<'),

{/} (' ','>','>',' ','<','>','>',' ','>',' ',' ','<','<',' ','>','>','>','>','>','>','>',' ','>','>','<',' ','<','<')

)

);

{ Правила исходной грамматики }

GramRules: array[1..RULE_NUM] of string =

('progEend.','E','E;E','E;','if(B)EelseE','if(B)E',

'beginEend','repeat(B)untilE','a:=E','BorB','BxorB','B',

'BandB','B','E<E','E>E','E=E','E<>E','(B)','not(B)',

'E-E','E+E','E','-E','E','(E)','a','c', 'E*E','E/E');

function MakeSymbolStr(iRuleNum: integer): string;

{ Функция корректировки отношений предшествования

для расширения матрицы предшествования }

function CorrectRule(cRule: char; lexTop,lexCur: TLexType;

symbStack: TList): char;

implementation

uses SyntSymb;

function MakeSymbolStr(iRuleNum: integer): string;

begin

if iRuleNum in [10..20] then Result := 'B'

else Result := 'E';

end;

function CorrectRule(cRule: char; lexTop,lexCur: TLexType;

symbStack: TList): char;

var j: integer;

begin

{ Корректируем отношение для символа "else", если в стеке

не логическое выражение }

Result := cRule;

if (cRule = '=') and (lexTop = LEX_CLOSE)

and (lexCur = LEX_ELSE) then

begin

j := TSymbStack(symbStack).Count-1;

if (j > 2)

and (TSymbStack(symbStack)[j-2].SymbolStr <> 'B')

then Result := '>';

end;

end;

end.

8. SyntSymb

unit SyntSymb;

interface

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

разбора с помощью алгоритма "сдвиг-свертка" на основе

матрицы операторного предшествования }

uses Classes, LexElem, SyntRule;

type

{ Два типа символов: терминальные (лексемы)

и нетерминальные (синтаксические) }

TSymbKind = (SYMB_LEX, SYMB_SYNT);

{ Структура данных для информации о символе грамматики }

TSymbInfo = record

{ Тип символа - терминальный или нетерминальный }

case SymbType: TSymbKind of

{ Для терминального символа - ссылка на лексему }

SYMB_LEX: (LexOne: TLexem);

{ Для нетерминального символа - ссылка на список

символов, из которых он был построен }

SYMB_SYNT: (LexList: TList);

end;

{ Предварительное описание класса "Символ" }

TSymbol = class;

{ Массив символов, составляющих правило грамматики }

TSymbArray = array[0..RULE_LENGTH] of TSymbol;

{ Структура, описывающая грамматический символ }

TSymbol = class(TObject)

protected

{ Информация о символе }

SymbInfo: TSymbInfo;

{ Номер правила, по которому создан символ }

iRuleNum: integer;

public

{ Конструктор создания терминального символа

на основе лексемы }

constructor CreateLex(Lex: TLexem);

{ Конструктор создания нетерминального символа

на основе правила и массива символов }

constructor CreateSymb(iR,iSymbN: integer;

const SymbArr: TSymbArray);

{ Деструктор для удаления символа }

destructor Destroy; override;

{ Функция получения символа из правила по порядковому

номеру символа }

function GetItem(iIdx: integer): TSymbol;

{ Функция, возвращающее количество символов

в исходном правиле }

function Count: integer;

{ Функция, формирующая строковое представление символа }

function SymbolStr: string;

{ Свойства символа на основе описанных выше

функций и данных }

{ Свойство, возвращающее тип символа }

property SymbType: TSymbKind read SymbInfo.SymbType;

{ Свойство, возвращающее ссылку на лексему

для терминального символа }

property Lexem: TLexem read SymbInfo.LexOne;

{ Свойство, возвращающее символа из правила

по порядковому номеру символа }

property Items[iIdx: integer]: TSymbol read GetItem;

default;

{ Свойство, возвращающее номер правила }

property Rule: integer read iRuleNum;

end;

{ Структура, описывающая синтаксический стек }

TSymbStack = class(TList)

public

{ Деструктор для удаления стека }

destructor Destroy; override;

{ Функция очистки стека }

procedure Clear; override;

{ Функция выборки символа по порядковому номеру

от конца стека }

function GetSymbol(iIdx: integer): TSymbol;

{ Функция помещения в стек входящей лексемы }

function Push(lex: TLexem): TSymbol;

{ Свойство для выборки символа по порядковому номеру

от вершины стека }

property Symbols[iIdx: integer]: TSymbol read GetSymbol;

default;

{ Функция, возвращающая самую верхнюю лексему в стеке }

function TopLexem: TLexem;

{ Функция, выполняющая свертку и помещающая новый символ

на вершину стека }

function MakeTopSymb: TSymbol;

end;

{ Функция, выполняющая алгоритм "сдвиг-свертка" }

function BuildSyntList(const listLex: TLexList;

symbStack: TSymbStack): TSymbol;

implementation

uses LexType, LexAuto;

constructor TSymbol.CreateLex(Lex: TLexem);

{ Конструктор создания терминального символа

на основе лексемы }

begin

{ Вызываем конструктор базового класа }

inherited Create;

{ Ставим тип символа "терминальный" }

SymbInfo.SymbType := SYMB_LEX;

{ Запоминаем ссылку на лексему }

SymbInfo.LexOne := Lex;

{ Правило не используется, поэтому "0" }

iRuleNum := 0;

end;

constructor TSymbol.CreateSymb(iR{номер правила},

iSymbN{кол-во исходных символов}: integer;

const SymbArr: TSymbArray{массив исходных символов});

{ Конструктор создания нетерминального символа

на основе правила и массива символов }

var i: integer;

begin

{ Вызываем конструктор базового класа }

inherited Create;

{ Ставим тип символа "нетерминальный" }

SymbInfo.SymbType := SYMB_SYNT;

{ Создаем список для хранения исходных символов }

SymbInfo.LexList := TList.Create;

{ Переносим все исходные символы в список

в обратном порядке }

for i:=iSymbN-1 downto 0 do

SymbInfo.LexList.Add(SymbArr[i]);

{ Запоминаем номер правила }

iRuleNum := iR;

end;

function TSymbol.GetItem(iIdx: integer): TSymbol;

{ Функция получения символа из правила

по порядковому номеру символа }

begin

Result := TSymbol(SymbInfo.LexList[iIdx])

end;

function TSymbol.Count: integer;

{ Функция, возвращающее количество символов

в исходном правиле }

begin

Result := SymbInfo.LexList.Count;

end;

function TSymbol.SymbolStr: string;

{ Функция, формирующая строковое представление символа }

begin

{ Если это нетерминальный символ, формируем его

представление в зависимости от номера правила }

if SymbType = SYMB_SYNT then

Result := MakeSymbolStr(iRuleNum)

{ Если это терминальный символ, формируем его

представление в соответствии со строковым

представлением лексемы }

else Result := Lexem.LexInfoStr;

end;

destructor TSymbol.Destroy;

{ Деструктор для удаления символа }

var i: integer;

begin

if SymbInfo.SymbType = SYMB_SYNT then

{ Если это нетерминальный символ }

with SymbInfo.LexList do

begin

{ Удаляем все его исходные символы из списка }

for i:=Count-1 downto 0 do TSymbol(Items[i]).Free;

{ Удаляем список символов }

Free;

end;

{ Вызываем деструктор базового класа }

inherited Destroy;

end;

destructor TSymbStack.Destroy;

{ Деструктор для удаления синтаксического стека }

begin

{ Очищаем стек }

Clear;

{ Вызываем деструктор базового класа }

inherited Destroy;

end;

procedure TSymbStack.Clear;

{ Функция очистки синтаксического стека }

var i: integer;

begin

{ Удаляем все символы из стека }

for i:=Count-1 downto 0 do TSymbol(Items[i]).Free;

{ Вызываем функцию базового класса }

inherited Clear;

end;

function TSymbStack.GetSymbol(iIdx: integer): TSymbol;

{ Функция выборки символа по порядковому номеру

от конца стека }

begin

Result := TSymbol(Items[iIdx]);

end;

function TSymbStack.TopLexem: TLexem;

{ Функция, возвращающая самую верхнюю лексему

в синтаксическом стеке }

var i: integer;

begin

Result := nil;

{ Для всех символов начиная от вершины стека }

for i:=Count-1 downto 0 do

{ Если это терминальный символ }

if Symbols[i].SymbType = SYMB_LEX then

begin

{ Берем ссылку на лексему }

Result := Symbols[i].Lexem;

{ Прекращаем поиск }

Break;

end;

end;

function TSymbStack.Push(lex: TLexem): TSymbol;

{ Функция помещения лексемы в синтаксический стек }

begin

{ Создаем новый терминальный символ }

Result := TSymbol.CreateLex(lex);

{ Добавляем его в стек }

Add(Result);

end;

function TSymbStack.MakeTopSymb: TSymbol;

{ Функция, выполняющая свертку и помещающая новый символ

на вершину стека.

Результат функции:

nil - если не удалось выполнить свертку, иначе ссылка

на новый нетерминальный символ - если свертка выполнена }

var

symCur: TSymbol; {текущий символ стека}

SymbArr: TSymbArray;

{массив для запоминания символов правила}

i,iSymbN: integer;

{счетчик символов стеке и счетчик символов в правиле}

sRuleStr: string; {строковое представление правила}

{ Функция добавления символа в правило }

procedure AddToRule(const sStr: string;{строка символа}

sym: TSymbol{тек. символ});

begin

{ Устанавливаем ссылку на текущий символ }

symCur := sym;

{ Добавляем очередной символ в массив символов правила }

SymbArr[iSymbN] := Symbols[i];

{ Добавляем его в строковое представление правила

(слева!) }

sRuleStr := sStr + sRuleStr;

{ Удаляем символ из стека }

Delete(i);

{ Увеличиваем счетчик символов в правиле }

Inc(iSymbN);

end;

begin

Result := nil;

{ Сбрасываем счетчик символов в правиле и

обнуляем текущий символ }

iSymbN := 0;

symCur := nil;

{ Строковое представление правила пустое }

sRuleStr := '';

{ Выполняем алгоритм для всех символов,

начиная с вершины стека }

for i:=Count-1 downto 0 do

begin

{ Если это нетерминальный (синтаксический) символ }

if Symbols[i].SymbType = SYMB_SYNT then

{ Добавляем его в правило, текущий символ при этом

не меняется }

AddToRule(Symbols[i].SymbolStr,symCur)

else

{ Если это терминальный символ и

текущий символ пустой }

if symCur = nil then

{ Добавляем его в правило и делаем текущим }

AddToRule(LexTypeInfo(Symbols[i].Lexem.LexType),

Symbols[i])

else

{ Если это терминальный символ и он связан

отношением "=" с текущим символов }

if GramMatrix[Symbols[i].Lexem.LexType,

symCur.Lexem.LexType] = '=' then

{ Добавляем его в правило и делаем текущим }

AddToRule(LexTypeInfo(Symbols[i].Lexem.LexType),

Symbols[i])

else

{ Иначе прерываем цикл, дальше искать не нужно }

Break;

{ Если превышена максимальная длина правила,

цикл прекращаем }

if iSymbN > RULE_LENGTH then Break;

end;

{ Если выбран хотя бы один символ из стека }

if iSymbN <> 0 then

begin

{ Ищем простым перебором правило, у которого строковое

представление совпадает с построенным

строковым представлением }

for i:=1 to RULE_NUM do

if GramRules[i] = sRuleStr then

begin

{ Если правило найдено, создаем новый

нетерминальный символ }

Result := TSymbol.CreateSymb(i,iSymbN,SymbArr);

{ И добавляем его в стека }

Add(Result);

{ Прерываем цикл поика правил }

Break;

end;

{ Если не был создан новый символ (правило не найдено),

надо удалить все исходные символы, это ошибка }

if Result = nil then

for i:=0 to iSymbN-1 do SymbArr[i].Free;

end;

end;

function BuildSyntList(

const listLex: TLexList{входная таблица лексем};

symbStack: TSymbStack{стек для работы алгоритма}

): TSymbol;

{ Функция, выполняющая алгоритм "сдвиг-свертка".

Результат функции:

- нетерминальный символ (корень синтаксического дерева),

если разбор был выполнен успешно;

- терминальный символ, ссылающийся на лексему, где была

обнаружена ошибка, если разбор выполнен с ошибками. }

var

i,iCnt: integer; {счетчик лексем и длина таблицы лексем}

lexStop: TLexem;

{ссылка на дополнительную начальную лексему}

lexTCur: TLexType;{тип текущей лексемы}

cRule: char;{текущее отношение предшествования}

begin

Result := nil;

{ Вычисляем длину входной таблицы лексем }

iCnt := listLex.Count-1;

{ Создаем дополнительную лексему "начало строки" }

lexStop := TLexem.CreateInfo('Начало файла',0,0,0);

try

{ Помещаем начальную лексему в стек }

symbStack.Push(lexStop);

{ Обнуляем счетчик входных лексем }

i := 0;

{ Цикл по всем лексемам от начала

до конца таблицы лексем }

repeat i<=iCnt do

begin

{ Получаем тип лексемы на вершине стека }

lexTCur := symbStack.TopLexem.LexType;

{ Если на вершине стека начальная лексема,

а текущая лексема - конечная,

то алгоритм разбора завершен }

if (lexTCur = LEX_START)

and (listLex[i].LexType = LEX_START) then Break;

{ Смотрим отношение лексемы на вершине стека

и текущей лексемы в строке }

cRule := GramMatrix[lexTCur,listLex[i].LexType];

{ Корректируем отношение. Если корректировка матрицы

предшествования не используется, то функция должна

вернуть то же самое отношение }

cRule := CorrectRule(cRule,lexTCur,

listLex[i].LexType,symbStack);

case cRule of

'<','=': { Надо выполнять сдвиг (перенос) }

begin

{ Помещаем текущую лексему в стек }

symbStack.Push(listLex[i]);

{ Увеличиваем счетчик входных лексем }

Inc(i);

end;

'>': { Надо выполнять свертку }

if symbStack.MakeTopSymb = nil then

{ Если не удалось выполнить свертку }

begin

{ Запоминаем текущую лексему как место ошибки }

Result := TSymbol.CreateLex(listLex[i]);

{ Прерываем алгоритм }

Break;

end;

else

{ Отношение не установлено - ошибочная ситуация }

begin

{ Запоминаем текущую лексему как место ошибки }

Result := TSymbol.CreateLex(listLex[i]);

{ Прерываем алгоритм }

Break;

end;

end{case};

end{repeat};

{ Если алгоритм прошел без ошибок }

if Result = nil then

begin

{ Проверяем, что в стеке осталось только 2 символа }

if symbStack.Count = 2 then

{ Если да, то верхний символ -

результат синтаксического разбора }

Result := symbStack[1]

{ Иначе это ошибка - отмечаем последнюю лексему

как место ошибки }

else Result := TSymbol.CreateLex(listLex[iCnt]);

end;

finally

{ Уничтожаем временную начальную лексему }

lexStop.Free;

end;

end;

end.

9. TrdOpt

unit TrdOpt;

interface

{ Модуль реализующий два алгоритма оптимизации:

- оптимизация путём свёртки объектного кода;

- оптимизация за счёт исключения лишних операций. }

uses Classes, TblElem, LexElem, TrdType, Triads;

type

{ Информационная структура для таблицы идентификаторов,

предназначенная для алгоритма свёртки объектного кода }

TConstInfo = class(TAddVarInfo)

protected

{ Поле для записи значения переменной }

iConst: longint;

{ Конструктор для создания структуры }

constructor Create(iInfo: longint);

public

{ Функции для чтения и записи информации }

function GetInfo(iIdx: integer): longint; override;

procedure SetInfo(iIdx: integer; iInfo: longint);

override;

end;

{ Информационная структура для таблицы идентификаторов,

предназначенная для алгоритма исключения лишних операций }

TDepInfo = class(TAddVarInfo)

protected

{ Поле для записи числа зависимости переменной }

iDep: longint;

{ Конструктор для создания структуры }

constructor Create(iInfo: longint);

public

{ Функции для чтения и записи информации }

function GetInfo(iIdx: integer): longint; override;

procedure SetInfo(iIdx: integer; iInfo: longint);

override;

end;

{ Процедура оптимизации методом свёртки объектного кода }

procedure OptimizeConst(listTriad: TTriadList);

{ Процедура оптимизации методом

исключения лишних операций }

procedure OptimizeSame(listTriad: TTriadList);

implementation

uses SysUtils, FncTree, LexType, TrdCalc;

constructor TConstInfo.Create(iInfo: longint);

{ Конструктор создания информационной структуры

для свёртки объектного кода }

begin

inherited Create;

iConst := iInfo;

end;

procedure TConstInfo.SetInfo(iIdx: integer;

iInfo: longint);

{ Функция записи инфоримации }

begin

iConst := iInfo;

end;

function TConstInfo.GetInfo(iIdx: integer): longint;

{ Функция чтения инфоримации }

begin

Result := iConst;

end;

function TestOperConst(Op: TOperand; listTriad: TTriadList;

var iConst: integer): Boolean;

{ Функция проверки того, что операнд является константой

и получения его значения в переменную iConst }

var pInfo: TConstInfo;

begin

Result := False;

{ Выборка по типу операнда }

case Op.OpType of

OP_CONST:

{ Если оператор - константа, то всё просто... }

begin

iConst := Op.ConstVal;

Result := True;

end;

OP_VAR:

{ Если оператор - переменная }

begin

{ тогда проверяем наличие у нее

информационной структуры }

pInfo := TConstInfo(Op.VarLink.Info);

if pInfo <> nil then

begin

{ и если такая структура есть,

берём ее значение }

iConst := pInfo[0];

Result := True;

end;

end;

OP_LINK:

{ Если оператор - ссылка на триаду }

begin

{ то он является константой,

если триада имеет тип "CONST" }

if listTriad[Op.TriadNum].TrdType = TRD_CONST

then

begin

iConst := listTriad[Op.TriadNum][1].ConstVal;

Result := True;

end;

end;

end{case};

end;

procedure OptimizeConst(listTriad: TTriadList);

{ Процедура оптимизации методом свёртки объектного кода }

var

i,j,iCnt,iOp1,iOp2: integer;

Ops: TOpArray;

Trd: TTriad;

begin

{ Очищаем информационные структуры

таблицы идентификаторов }

ClearTreeInfo;

{ Заполняем операнды для триады типа "CONST" }

Ops[1].OpType := OP_CONST;

Ops[2].OpType := OP_CONST;

Ops[2].ConstVal := 0;

iCnt := listTriad.Count-1;

{ Для всех триад списка выполняем алгоритм }

for i:=0 to iCnt do

begin

Trd := listTriad[i];

if Trd.TrdType in TriadLineSet then

begin

{ Если любой операнд линейной триады ссылается

на триаду типа "CONST",

то берём и запоминаем её значение }

for j:=1 to 2 do

if (Trd[j].OpType = OP_LINK)

and (listTriad[Trd.Links[j]].TrdType = TRD_CONST)

then

begin

Trd.OpTypes[j] := OP_CONST;

Trd.Values[j] :=

listTriad[Trd.Links[j]][1].ConstVal;

end;

end

else

if Trd.TrdType = TRD_IF then

begin

{ Если первый операнд условной триады ссылается

на триаду типа "CONST",

то берём и запоминаем её значение }

if (Trd[1].OpType = OP_LINK)

and (listTriad[Trd.Links[1]].TrdType = TRD_CONST)

then

begin

Trd.OpTypes[1] := OP_CONST;

Trd.Values[1] :=

listTriad[Trd.Links[1]][1].ConstVal;

end;

end

else

if Trd.TrdType = TRD_ASSIGN then

begin

{ Если второй операнд триады присвоения

ссылается на триаду типа "CONST",

то берём и запоминаем её значение }

if (Trd[2].OpType = OP_LINK)

and (listTriad[Trd.Links[2]].TrdType = TRD_CONST)

then

begin

Trd.OpTypes[2] := OP_CONST;

Trd.Values[2] :=

listTriad[Trd.Links[2]][1].ConstVal;

end;

end;

{ Если триада помечена ссылкой, то линейный участок

кода закончен - опять очищаем информационные

структуры таблицы идентификаторов }

if Trd.IsLinked then ClearTreeInfo;

{ Если триада имеет тип "присвоение" }

if Trd.TrdType = TRD_ASSIGN then

begin

{ И если её второй операнд - константа }

if TestOperConst(Trd[2],listTriad,iOp2) then

{ запоминаем его значение в информационной

структуре переменной }

Trd[1].VarLink.Info := TConstInfo.Create(iOp2);

end

else

{ Если триада - одна из линейных операций }

if Trd.TrdType in TriadLineSet then

begin

{ И если оба её операнда - константы }

if TestOperConst(Trd[1],listTriad,iOp1)

and TestOperConst(Trd[2],listTriad,iOp2) then

begin

{ тогда вычисляем значение операции }

Ops[1].ConstVal :=

CalcTriad(Trd.TrdType,iOp1,iOp2);

{ запоминаем его в триаде типа "CONST",

которую записываем в список

вместо прежней триады }

listTriad.Items[i] := TTriad.Create(TRD_CONST,Ops);

{ Если на прежнюю триаду была ссылка,

сохраняем её }

listTriad[i].IsLinked := Trd.IsLinked;

{ Уничтожаем прежнюю триаду }

Trd.Free;

end;

end;

end;

end;

constructor TDepInfo.Create(iInfo: longint);

{ Конструктор создания информационной структуры

для чисел зависимости }

begin

inherited Create;

iDep := iInfo;

end;

procedure TDepInfo.SetInfo(iIdx: integer; iInfo: longint);

{ Функция записи числа зависимости }

begin

iDep := iInfo;

end;

function TDepInfo.GetInfo(iIdx: integer): longint;

{ Функция чтения числа зависимости }

begin

Result := iDep;

end;

function CalcDepOp(listTriad: TTriadList;

Op: TOperand): longint;

{ Функция вычисления числа зависимости

для операнда триады }

begin

Result := 0;

{ Выборка по типу операнда }

case Op.OpType of

OP_VAR:

{ Если это переменная - смотрим ее информационную

структуру, и если такая структура есть,

то берем оттуда число зависимости }

if Op.VarLink.Info <> nil then Result :=

Op.VarLink.Info.Info[0];

OP_LINK:

{ Если это ссылка на триаду,

то берем число зависимости триады }

Result := listTriad[Op.TriadNum].Info;

end{case};

end;

function CalcDep(listTriad: TTriadList;

Trd: TTriad): longint;

{ Функция вычисления числа зависимости триады }

var iDepTmp: longint;

begin

Result := CalcDepOp(listTriad,Trd[1]);

iDepTmp := CalcDepOp(listTriad,Trd[2]);

{ Число зависимости триады есть на единицу большее,

чем максимальное из чисел зависимости её операндов }

if iDepTmp > Result then Result := iDepTmp+1

else Inc(Result);

Trd.Info := Result;

end;

procedure OptimizeSame(listTriad: TTriadList);

{ Процедура оптимизации методом исключения

лишних операций }

var

i,j,iStart,iCnt,iNum: integer;

Ops: TOpArray;

Trd: TTriad;

begin

{ Ставим начало линейного участка равным

началу списка триад }

iStart := 0;

{ Очищаем информационные структуры

таблицы идентификаторов }

ClearTreeInfo;

iCnt := listTriad.Count-1;

{ Заполняем операнды для триады типа "SAME" }

Ops[1].OpType := OP_LINK;

Ops[2].OpType := OP_CONST;

Ops[2].ConstVal := 0;

{ Для всех триад списка выполняем алгоритм }

for i:=0 to iCnt do

begin

Trd := listTriad[i];

{ Если триада помечена ссылкой, то линейный участок

кода закончен - опять очищаем информационные

структуры таблицы идентификаторов,

и запоминаем начало нового линейного участка }

if Trd.IsLinked then

begin

ClearTreeInfo;

iStart := i;

end;

{ Если любой операнд триады ссылается на триаду

типа "SAME", то переставляем ссылку на предыдущую,

совпадающую с ней триаду }

for j:=1 to 2 do

if Trd[j].OpType = OP_LINK then

begin

iNum := Trd[j].TriadNum;

if listTriad[iNum].TrdType = TRD_SAME then

Trd.Links[j] := listTriad[iNum].Links[1];

end;

{ Если триада типа "присвоение",

то запоминаем число зависимости переменной }

if Trd.TrdType = TRD_ASSIGN then

begin

Trd[1].VarLink.Info := TDepInfo.Create(i+1);

end

else

{ Если триада - одна из линейных операций }

if Trd.TrdType in TriadLineSet then

begin

{ Вычисляем число зависимости триады }

CalcDep(listTriad,Trd);

{ На всем линейном участке ищем совпадающую с ней

триаду с таким же числом зависимости }

for j:=iStart to i-1 do

begin

if Trd.IsEqual(listTriad[j])

and (Trd.Info = listTriad[j].Info) then

begin

{ Если такая триада найдена, запоминаем

ссылку на нее }

Ops[1].TriadNum := j;

{ запоминаем её в триаде типа "SAME", которую

записываем в список вместо прежней триады }

listTriad.Items[i] :=

TTriad.Create(TRD_SAME,Ops);

{ Если на прежнюю триаду была ссылка,

сохраняем её }

listTriad[i].IsLinked := Trd.IsLinked;

{ Уничтожаем прежнюю триаду }

Trd.Free;

{ Прерываем поиск }

Break;

end;

end;

end{if};

end{for};

end;

end.

10. Triads

unit Triads;

interface

{ Модуль, обеспечивающий работу с триадами

и списком триад }

uses Classes, TblElem, LexElem, TrdType;

type

{ Предварительное описание класса триад }

TTriad = class;

{ Типы операндов: константа, переменная,

ссылка на другую триаду }

TOpType = (OP_CONST, OP_VAR, OP_LINK);

{ Структура данных для описания операнда в триадах }

TOperand = record

{ Тип операнда }

case OpType: TOpType of

OP_CONST: (ConstVal: integer);

{ для константы - её значение }

OP_VAR: (VarLink: TVarInfo);

{ для переменной - ссылка на элемент

таблицы идентификаторов }

OP_LINK: (TriadNum: integer);

{ для триады - номер триады }

end;

{ Массив операндов из двух элементов }

TOpArray = array[1..2] of TOperand;

{ Структура данных для описания триады }

TTriad = class(TObject)

private

{ Тип триады }

TriadType: TTriadType;

{ Массив операндов }

Operands: TOpArray;

public

{ Дополнительная информация для оптимизирующих алгоритмов }

Info: longint;

{ Флаг наличия ссылки на эту триаду }

IsLinked: Boolean;

{ Конструктор для создания триады }

constructor Create(Typ: TTriadType; const Ops: TOpArray);

{ Функции для чтения и записи операндов }

function GetOperand(iIdx: integer): TOperand;

procedure SetOperand(iIdx: integer; Op: TOperand);

{ Функции для чтения и записи ссылок на другие триады }

function GetLink(iIdx: integer): integer;

procedure SetLink(iIdx: integer; TrdN: integer);

{ Функции для чтения и записи типа операндов }

function GetOpType(iIdx: integer): TOpType;

procedure SetOpType(iIdx: integer; OpT: TOpType);

{ Функции для чтения и записи значений констант }

function GetConstVal(iIdx: integer): integer;

procedure SetConstVal(iIdx: integer; iVal: integer);

{ Свойства триады, основанные на описанных выше

функциях }

property TrdType: TTriadType read TriadType;

property Opers[iIdx: integer]: TOperand read GetOperand

write SetOperand; default;

property Links[iIdx: integer]: integer read GetLink

write SetLink;

property OpTypes[iIdx: integer]: TOpType read GetOpType

write SetOpType;

property Values[iIdx: integer]: integer read GetConstVal

write SetConstVal;

{ Функция, проверяющая совпадение (эквивалентность)

двух триад }

function IsEqual(Trd1: TTriad): Boolean;

{ Функция, формирующая строковое представление триады }

function MakeString(i: integer): string;

end;

{ Класс для описания списка триад и работы с ним }

TTriadList = class(TList)

public

{ Процедура очистки списка и деструктор

для удаления списка }

procedure Clear; override;

destructor Destroy; override;

{ Процедура вывода списка триад в список строк

для отображения списка триад }

procedure WriteToList(list: TStrings);

{ Процедура удаления триады из списка }

procedure DelTriad(iIdx: integer);

{ Функция получения триады из списка по её номеру }

function GetTriad(iIdx: integer): TTriad;

{ Свойство списка триад для доступа к нему

по номеру триады }

property Triads[iIdx: integer]: TTriad read GetTriad;

default;

end;

{ Процедура удаления из списка триад

всех триад заданного типа }

procedure DelTriadTypes(listTriad: TTriadList;

TrdType: TTriadType);

implementation

uses SysUtils, FncTree, LexType;

constructor TTriad.Create(Typ: TTriadType;

const Ops: TOpArray);

{ Конструктор создания триады }

var i: integer;

begin

{ Вызываем конструктор базового класса }

inherited Create;

{ Запоминаем тип триады }

TriadType := Typ;

{ Запоминаем два операнда триады }

for i:=1 to 2 do Operands[i] := Ops[i];

{ Очищаем поле дополнительной информации

и поле внешней ссылки }

Info := 0;

IsLinked := False;

end;

function TTriad.GetOperand(iIdx: integer): TOperand;

{ Функция получения данных об операнде триады

по его номеру }

begin

Result := Operands[iIdx];

end;

procedure TTriad.SetOperand(iIdx: integer; Op: TOperand);

{ Функция записи данных операнда триады по его номеру }

begin

Operands[iIdx] := Op;

end;

function TTriad.GetLink(iIdx: integer): integer;

{ Функция получения ссылки на другую триаду из операнда

по его номеру }

begin

Result := Operands[iIdx].TriadNum;

end;

procedure TTriad.SetLink(iIdx: integer; TrdN: integer);

{ Функция записи номера ссылки на другую триаду

в операнд по его номеру }

begin

Operands[iIdx].TriadNum := TrdN;

end;

function TTriad.GetOpType(iIdx: integer): TOpType;

{ Функция получения типа операнда по его номеру }

begin

Result := Operands[iIdx].OpType;

end;

function TTriad.GetConstVal(iIdx: integer): integer;

{ Функция записи типа операнда по его номеру }

begin

Result := Operands[iIdx].ConstVal;

end;

procedure TTriad.SetConstVal(iIdx: integer; iVal: integer);


Подобные документы

  • Огляд існуючих методів розробки компіляторів, детальний опис мови. Характеристика та специфіка процесу розробки програми компілятора на рівні блок-схем і тексту програми. Подання тексту компілятора, а також результатів тестування розробленої програми.

    курсовая работа [510,2 K], добавлен 03.06.2011

  • Методика розробки компілятору з вхідної мови програмування Pascal, оболонка, якого розроблена в середовищі програмування Borland C під операційну систему Windows. Блок-схема програми. Розробка оптимізатора та генератора коду. Тестування компілятора.

    курсовая работа [218,6 K], добавлен 04.06.2011

  • Поняття компілятора та теоретичні основи його роботи. Введення коду програми завантаженням текстового файлу. Опрацювання тексту лексичним та синтаксичним аналізаторами. Генерація та оптимізанія об'єктного коду. Побудова графічного інтерфейсу програми.

    курсовая работа [586,6 K], добавлен 22.01.2014

  • Мови програмування, на яких написана програма побудови замкнутих багатокутників. Функціональні обмеження на застосування. Методи та елементи, що використовуються. Структура програми з описом функцій складових частин. Зв'язок програми з іншими програмами.

    курсовая работа [76,6 K], добавлен 01.04.2016

  • Створення додатку який дозволяє будувати діаграми динаміки обсягів промислового виробництва засобами інтегрованого середовища Borland Builder C++ 6.0 на мові програмування високого рівня С++. Опис структури інтерфейсу та складових частин програми.

    курсовая работа [2,0 M], добавлен 15.01.2014

  • Розробка програми для моделювання роботи алгоритму Дейкстри мовою C# з використанням об’єктно-орієнтованих принципів програмування. Алгоритм побудови робочого поля. Програмування графічного інтерфейсу користувача. Тестування програмного забезпечення.

    курсовая работа [991,4 K], добавлен 06.08.2013

  • Середовище розробки програм Borland Delphi, робота компонентів. Створення нових компонентів та використання компонентів Delphi для роботи з базами даних. Системи керування базами даних InterBase та Firebird. Компоненти Delphi для роботи з СКБД FireBird.

    реферат [71,4 K], добавлен 12.04.2010

  • Проектування гнучкої спеціалізованої системи генерації тестових завдань, яка відбувається на основі параметричної моделі з використанням зовнішніх компіляторів мов програмування Pascal і Borland C++. Середовище Delphi, як засіб розробки даної програми.

    дипломная работа [2,4 M], добавлен 26.10.2012

  • Основні відомості про історію розвитку мови Object Pascal, середовища Delphi, їх основні технології та застосування для роботи з файлами. Опис основних особливостей мови, основних елементів програмної мови. Принципи об'єктно-орієнтованого програмування.

    курсовая работа [471,5 K], добавлен 12.04.2010

  • Розгляд матеріалу з розрахунку рецептур. Аналоги програм та сайтів по розрахунку рецептур, створення алгоритму побудови програми. Оптимізація калькулятору з розрахунку рецептур. Проектування алгоритму та програмного забезпечення для його реалізації.

    курсовая работа [52,0 M], добавлен 28.03.2023

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.