Автор: Пользователь скрыл имя, 10 Мая 2011 в 21:35, лабораторная работа
Цель работы:
Изучение основных понятий теории грамматик простого и операторного предшествования, ознакомление с алгоритмами синтаксического анализа (разбора) для некоторых классов КС-грамматик, получение практических навыков создания простейшего синтаксического анализатора для заданной грамматики операторного предшествования.
в таблице }
begin
{ Цикл по всем прочитанным лексемам }
GridLex.RowCount := listLex.Count+1;
iCnt := listLex.Count-1;
for i:=0 to iCnt do
begin
{ Первая колонка - номер }
GridLex.Cells[0,i+1] := IntToStr(i+1);
{ Вторая колонка - тип лексемы }
GridLex.Cells[1,i+1] :=
LexTypeName(listLex[i].
{ Третья колонка - значение лексемы }
GridLex.Cells[2,i+1] := listLex[i].LexInfoStr;
end;
{ Добавляем в конец списка лексем информационную
лексему "конец строки" }
with ListIdents do
listLex.Add(TLexem.CreateInfo(
Length(Text),Lines.Count-1,0))
{ Строим дерево синтаксического разбора и
получаем ссылку на его корень }
symbRes
:= BuildSyntList(listLex,
{ Если эта ссылка содержит лексические данные,
значит была ошибка в месте, указанном лексемой }
if symbRes.SymbType = SYMB_LEX then
begin
MessageDlg(
Format('Синтаксическая ошибка в строке %d!',
[symbRes.Lexem.StrNum+1]),
mtWarning,[mbOk],0);
{ Берем позицию ошибочной лексемы по ссылке
и позиционируем на нее список строк }
ListIdents.SelStart := symbRes.Lexem.PosAll;
ListIdents.SetFocus;
{ Освобождаем ссылку на лексему }
symbRes.Free;
end
else
{ Если не было синтаксической ошибки,
заполняем дерево
begin
{ Записываем данные в корень дерева }
nodeTree := TreeSynt.Items.Add(nil,
{ Строим остальные элементы
MakeTree(nodeTree,symbRes);
{ Раскрываем всё дерево }
nodeTree.Expand(True);
{ Позиционируем указатель на корневой элемент }
TreeSynt.Selected := nodeTree;
end;
end;
end;
procedure TLab3Form.MakeTree(
{ Процедура отображения синтаксического дерева }
nodeTree: TTreeNode;
{ссылка на корневой элемент отображаемой
части дерева на экране}
symbSynt: TSymbol
{ссылка на синтаксический символ, связанный
с корневым элементом этой части дерева});
var
i,iCnt: integer;
nodeTmp: TTreeNode;
begin
{ Берем количество дочерних вершин для текущей }
iCnt := symbSynt.Count-1;
{ Цикл по всем дочерним вершинам }
for i:=0 to iCnt do
begin
{ Добавляем к дереву на экране вершину и
запоминаем ссылку на нее }
nodeTmp
:= TreeSynt.Items.AddChild(
{ Если эта вершина связана с нетерминальным символом,
рекурсивно вызываем процедуру построения дерева
для нее }
if symbSynt[i].SymbType = SYMB_SYNT then
MakeTree(nodeTmp,symbSynt[i]);
end;
end;
procedure TLab3Form.BtnExitClick(Sender: TObject);
{ Завершение работы с программой }
begin
Self.Close;
end;
end.
unit LexAuto; {
interface
{ Модуль, обеспечивающий построение таблицы лексем
по исходному
тексту программы }
uses Classes, TblElem, LexType,
LexElem;
{ Функция создания списка лексем
по исходному тексту программы }
function MakeLexList(listFile: TStrings;
listLex: TLexList): integer;
implementation
uses SysUtils, FncTree;
type
{ Перечень всех возможных состояний конечного автомата }
TAutoPos = (
AP_START,AP_THEN1,AP_THEN2,AP_
AP_ELSE1,AP_ELSE2,AP_ELSE3,AP_
AP_ASSIGN,AP_VAR,AP_CONST,AP_
function MakeLexList(listFile: TStrings;listLex: TLexList): integer;
{ Функция создания списка лексем
по исходному тексту программы }
var
i,j,iCnt,iStr, { Переменные и счетчики циклов }
iAll, { Счетчик общего количества входных символов }
iStComm,iStart,comm_pos: integer;
{ Переменные для запоминания позиции начала лексемы }
posCur: TAutoPos; { Текущее состояние КА }
sCurStr,sTmp: string;
{ Строки
для временного хранения
{ Несколько простых
процедур для работы со
procedure AddVarToList(posNext: TAutoPos; iP: integer);
{ Процедура добавления переменной в список }
begin
{ Выделяем имя переменной из текущей строки }
sTmp := System.Copy(sCurStr,iStart,iP-
{ При создании переменной она сначала заносится в таблицу
идентификаторов, а потом ссылка на нее -
в таблицу лексем }
listLex.Add(TLexem.CreateVar(
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure AddVarKeyToList(keyAdd: TLexType;
posNext: TAutoPos);
{ Процедура добавления переменной и разделителя в список }
begin
{ Выделяем имя переменной из текущей строки }
sTmp := System.Copy(sCurStr,iStart,j-
{ При создании переменной она сначала заносится в таблицу
идентификаторов, а потом ссылка на нее -
в таблицу лексем }
listLex.Add(TLexem.CreateVar(
listLex.Add(TLexem.CreateKey(
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure AddConstToList(posNext: TAutoPos; iP: integer);
{ Процедура добавления константы в список }
begin
{ Выделяем константу из текущей строки }
sTmp := System.Copy(sCurStr,iStart,iP-
{ Заносим константу в список вместе с ее значением }
listLex.Add(TLexem.
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure AddConstKeyToList(keyAdd: TLexType;
posNext: TAutoPos);
{ Процедура добавления константы и разделителя в список }
begin
{ Выделяем константу из текущей строки }
sTmp := System.Copy(sCurStr,iStart,j-
{ Заносим константу в список вместе с ее значением }
listLex.Add(TLexem.
listLex.Add(TLexem.CreateKey(
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure AddKeyToList(keyAdd: TLexType;
posNext: TAutoPos);
{ Процедура добавления
ключевого или разделителя
в список }
begin
listLex.Add(TLexem.CreateKey(
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure Add2KeysToList(keyAdd1,
posNext: TAutoPos);
{ Процедура добавления ключевого слова и разделителя
в список подряд }
begin
listLex.Add(TLexem.CreateKey(
listLex.Add(TLexem.CreateKey(
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_SEMI,AP_
'>':
AddVarKeyToList(LEX_GT,AP_
'<':
AddVarKeyToList(LEX_LT,AP_
'=': AddVarKeyToList(LEX_EQ,AP_
'{': begin AddVarToList(AP_COMM,j); comm_pos:=i;end;
' ',#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
':': AddKeyToList(keyAdd,AP_ASSIGN)
'=': Add2KeysToList(keyAdd,LEX_EQ,
'>':
Add2KeysToList(keyAdd,LEX_GT,
'<':
Add2KeysToList(keyAdd,LEX_LT,
';': Add2KeysToList(keyAdd,LEX_
'0'..'9','A'..'Z','a'..'z','_'
'{': begin AddKeyToList(keyAdd,AP_COMM); comm_pos:=i;end;
' ',#10,#13,#9: AddKeyToList(keyAdd,AP_START);
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