Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
36
Добавлен:
02.05.2014
Размер:
13.42 Кб
Скачать
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;
{ Цикл по всем лексемам от начала
до конца таблицы лексем }
while 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{while};
{ Если алгоритм прошел без ошибок }
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.

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