Руководство пользователя. После запуска программы пользователю предлагается ввести КС-грамматику (ограничение




После запуска программы пользователю предлагается ввести КС-грамматику (ограничение при вводе: длина нетерминала не больше восьми символов). Ввод строки заканчивается нажатием клавиши Enter. Для определения в программе нетерминала используются символы ‘<’ и ‘>’ непосредственно между которыми находится нетерминал, знак или ‘|’, знак присвоить ‘:=’. Новая строка обязательно должна начинаться с нетерминала и последующим символом(и) ‘:=’.

Для начала анализа введённой КС-грамматике нужно нажать клавишу F5 или выбрать в меню пункт «Запуск» (меню вызывается нажатием F9). Перед тем как начать построение матрицы предшествования производится синтаксический анализ введенного текста.

 

Возможные ошибки при вводе грамматики:

 

После символа ‘|’ должен обязательно следовать терминал или нетерминал.

 

 

В грамматике описан нетерминал <F>, но он нигде не используется (отсутствует в правой части).

 

 

В грамматике отсутствует описание нетерминала <ZZZ> (отсутствует в правой части)

 

Если грамматика введена верно, то начинается построение матрицы (алгоритм описан выше). При возникновении ошибки (один или несколько (не)терминалов имеют более чем одно отношение предшествования) выводится сообщение и в соответствующую ячейку записывается символ Х.

После этого выполняется линеаризация матрицы с помощью графа: для упрощения алгоритма в матрице сначала ведется поиск отношений = при нахождении таковых выполняется склеивание соответствующих вершин. Эта операция избавляет нас от рутинных действий связанных с «перестановкой» связей. Также упрощается описание графа в программе: надобность в хранении связей отсутствует - необходимо лишь хранить количество входящих и выходящих ребер. При построении векторов граф, проверяется на цикличность (при существовании цикла выводится сообщении о невозможности построения функции предшествования).


Текст программы

 

Program KP;

Uses TpCrt,Graph,GrText,DataUnit;

Const Txt='По заданной КС-грамматике построить отношение простого'+

' или операторного предшествования и функцию предшествования,'+

' используя граф линеаризации и алгоритм пересчета с визуализацией'+

' шагов построения графа';

Errors: array [0..10] of String[34] ={ошибки}

(' КС-грамматика синтаксически верна',{0}

' Ожидается ~"<"', {1}

' Ожидается ~">"', {2}

' Ожидается ~":="', {3}

' Требуется нетерминал', {4}

' Требуется терминал', {5}

' Неопределенный нетерминал', {6}

' Неиспользуемый нетерминал', {7}

' Требуется терминал или нетерминал',{8}

' Многоопределенный нетерминал', {9}

' Найдены недопустимые символы'); {10}

menu:array[1..5] of string[10]=

('Открыть','Сохранить','Запуск','Информация','Выход');

Type

notTerm=^List;

List=Record{список терминалов и нетерминалов}

Name:Str10;{терминал или нетерминал}

Next:notTerm;

End;

strBuf=array [1..800] of Char;

matrixPr=array [1..20,1..20] of 0..4;

Var i:Byte;{текущая позиция}

s:String;{текущая строка}

Len:Byte absolute s;

str_:strBuf;{общий буфер для текста}

LenStr:Integer;{всего символов в буфере}

CLine,{кол-во строк}

y:Byte;{текущая строка}

CTerm:Byte;{кол-во нетерминалов}

CTrmNotTrm:Byte;{кол-во нетерминалов и терминалов}

notTerminalS:NotTerm;{нетерминалы встречающиеся в правых частях}

notTerminalL:NotTerm;{нетерминалы в левой части}

Trm_notTrm:NotTerm;{список терминалов и нетерминалов}

LTN:NotTerm;{левые}

RTN:NotTerm;{правые}

tmp:NotTerm;{временная переменная}

matrixPrecede:matrixPr;

LenWin:Byte;{ширина окна}

{$I Dinamic.inc} {процедуры для работы с динамическими переменными}

{$I GraphPr.inc} {графический интерфейс}

{$I ServFunc.inc} {дополнительные процедуры обработки строки}

{----------------------------------------------------------------------------}

Procedure Blank;

(* пропуск управляющих символов и пробелов *)

Begin

While (i<=Len) and (S[i] = #32) do inc(i);

End;

{}

Function Let(s:Char):Boolean;

(* контроль букв *)

Begin

Let:=((s) >= 'A') and ((s) <= 'Z') or (s in RusLetters);

End;

{}

Function Dig (s:Char;Var n:Byte):Boolean;

(* контроль цифр *)

Begin

If (s >= '0') and (s <= '9') Then

Begin

n:=ord(s)-48;

Dig:=true

End

Else Dig:=false

End;

{}

Function Terminal (Var term:String):Boolean;

(* поиск терминала *)

Begin

term:='';

If i<=Len Then

While (i<=Len) and (S[i] in Digits+LatLetters+Punctuation+Service+RusLetters)

and not (s[i]='<') and not (s[i]='>') and not (s[i]='|') Do

Begin

term:=term+s[i];

inc(i);

End;

Terminal:=term > '';

End;

{}

Function notTerminal (Var term:String):Boolean;

(* поиск нетерминала *)

Var

j:word;

n:Byte;

Ex:Boolean;

Begin

Blank;

j:=i;

term:='';

Ex:=True;

If i<=Length(s) Then

If Let(S[i]) Then

Begin

While (i<=Length(s)) and Let(S[i]) or Dig(S[i],n) do

Begin

If (i-j) < 9 Then term:=term+S[i];

inc(i);

End;

If (i-j) > 8 Then

Ex:=False

Else

Blank;

End

Else

Ex:=False

Else

Ex:=False;

notTerminal:=Ex;

End;

{}

Procedure Check;

Var term:String;

Exist,Ex:Boolean;

notT:List;

k:Byte;

Label notTerminalOrTerminal,

OrS,LineS,EndS,Start,New,Gluk;

Begin

Goto Start;

New:{при возникновении ошибки}

DeleteList(NotTerminalS);

DeleteList(NotTerminalL);

DeleteList(Trm_NotTrm);

If not InputText Then Exit;

Start:{один раз}

i:=1;

y:=1;

k:=1;

CTerm:=0;

CTrmNotTrm:=0;

PosStr(1,s);{первая строка}

If s='' Then

Goto New;

LineS:{новая строка}

GotoXY(1,10);Write(s+' Длина анализ.строки ',Length(s),' '+#13#10,'y=',y,' всего строк ',Cline);

Blank;

If not (s[i]='<') Then

Begin

Error(1);

Goto New;

End

Else

Begin

inc(i);

Blank;

If not notTerminal(term) Then

Begin

Error(4);

Goto New;

End

Else

Begin{есть нетерминал}

Blank;

If not (s[i]='>') Then

Begin

Error(2);

Goto New;

End

Else{записываем нетерминал}

Begin

NotT.Name:='<'+term+'>';

If Search(NotTerminalL,NotT)>0 Then

Begin{многоопределенный}

Error(9);

Goto New;

End;

If Search(Trm_NotTrm,NotT)=0 Then

Begin

Complete(Trm_NotTrm,NotT);{в общий список теминалов&нетерминалов}

inc(CTrmNotTrm);

End;

Complete(NotTerminalL,NotT);{лев. часть}

inc(CTerm);

inc(i);

Blank;

If not (Copy(s,i,2)=':=') Then

Begin

Error(3);

Goto New;

End

Else

Begin{есть:=}

inc(i,2);

notTerminalOrTerminal:{после:= обязательный терминал или нетерминал}

Blank;

If s[i]='<' Then{нетерминал}

Begin

inc(i);

Blank;

If notTerminal(term) Then

Begin{есть нетерминал}

Blank;

If s[i]='>' Then{записываем нетерминал}

Begin

NotT.Name:='<'+term+'>';

Complete(NotTerminalS,NotT);

If Search(Trm_NotTrm,NotT)=0 Then

Begin

Complete(Trm_NotTrm,NotT);{в общий список теминалов&нетерминалов}

inc(CTrmNotTrm);

End;

inc(i);

Blank;

Goto OrS;{может быть знак ИЛИ}

End

Else

Begin

Error(2);{нет >}

Goto New;

End

End

Else

Begin

Error(4);{нет нетерминала, но < есть}

Goto New;

End

End

Else{терминал}

If Terminal(term) Then{записываем терминал}

Begin

NotT.Name:=term;

If Search(Trm_NotTrm,NotT)=0 Then

Begin

Complete(Trm_NotTrm,NotT);{в общий список теминалов&нетерминалов}

inc(CTrmNotTrm);

End;

Blank;

Goto OrS;

End

Else

Begin

Error(8);{нет нетерминала или терминала}

Goto New;

End;

OrS: If i>Len Then Goto Gluk;{обходим глюк}

If s[i]='|' Then{знак ИЛИ}

Begin

inc(i);

Goto notTerminalOrTerminal

End

Else{знака ИЛИ нет}

Begin

Blank;

If i>Len Then{конец строки?}

Gluk: If y<CLine Then{дошли до конца строки}

Begin

{следующ. стр}

inc(y);

posStr(y,s);

If s='' Then Goto EndS;

i:=1;

Goto LineS;

End

Else{конец файла}

Goto EndS

Else Goto notTerminalOrTerminal;{знака ИЛИ нет}

End;

End;

End;

End;

End;

EndS:

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

tmp:=NotTerminalL^.Next;{пропускаем первый}

exist:=True;

y:=2;

While (tmp<>Nil) and Exist Do

Begin

NotT:=tmp^;

Exist:=Search(NotTerminalS,NotT)>0;

tmp:=tmp^.Next;

inc(y);

End;

dec(y);

i:=1;

While (i<=y) Do

Begin{позицианируем на нужную строку}

{в s строка с ошибкой}

posStr(y,s);

inc(i);

End;

If not Exist Then{неиспользуемый нетерминал}

Begin

i:=1;

Error(7);

Goto New;

End;

{----------------}

tmp:=NotTerminalS;

exist:=True;

While (tmp<>Nil) and Exist Do

Begin

NotT:=tmp^;

Exist:=Search(NotTerminalL,NotT)>0;

tmp:=tmp^.Next;

End;

If not Exist Then{неопределенный нетерминал}

Begin

i:=1;

y:=0;

Ex:=False;

While not Ex Do

Begin{позицианируем на нужную строку}

inc(y);

PosStr(y,s);{в s строка с ошибкой}

i:=Pos(NotT.name,s);

Ex:=i>0;

End;

Error(6);

Goto New;

End;

Window(5,21,59,25);

TextColor(15);

TextBackGround(1);

WriteLN(Errors[0]);

readkey;

End;

Procedure SearchLR;

Function SearchInBlock(n:Byte;l:NotTerm;inf:List):Byte;

Var j:Byte;

Ex:Boolean;

Begin

If l<>Nil Then

Begin

j:=1;

While (l<>Nil) and (n<>j) Do

Begin

If l^.Name=#0 Then inc(j);

l:=l^.Next;

End;

Ex:=False;

While (l<>nil) and (l^.Name<>inf.Name) and Not Ex Do

Begin

inc(j);

If l^.Name=#0 Then Ex:=True;

l:=l^.next;

End;

End;

If (l=Nil) or Ex Then SearchInBlock:=0

Else SearchInBlock:=j;

End;

Procedure InsListInBlock(n:Byte; l:NotTerm;x,d:List);

Var q:NotTerm;

j:Byte;

Begin

If l=Nil Then WriteLN('Внимание! Внутренняя ошибка 03')

Else

Begin

j:=1;

While (l<>Nil) and (n<>j) Do

Begin

If l^.Name=#0 Then inc(j);

l:=l^.Next;

End;

While (l<>Nil) and (l^.Name<>x.Name) Do

l:=l^.Next;

If l<>Nil Then

Begin

new(q);

q^.Name:=d.Name;

q^.Next:=l^.Next;

l^.Next:=q;

End;

End;

End;

Procedure Add_(ListLR:NotTerm);

Var tmp,p:NotTerm;

tmp2:NotTerm;

tmpName:Str10;

y,j:Byte;

inf:List;

inf2:List;

Begin

y:=1;

tmp:=ListLR;{список с разделителями}

p:=tmp;

Repeat

{ищем нетерминал (в левых или правых)}

tmp:=p;

tmp2:=NotTerminalL;

While (tmp<>Nil) and (Pos('<',tmp^.Name)<>1) Do

Begin

If tmp^.Name=#0 Then inc(y);

tmp:=tmp^.Next;

End;

If tmp=Nil Then p:=Nil

Else If tmp^.Next<>Nil Then

p:=tmp^.Next{сохраняем позицию указатель на следующий}

Else p:=Nil;

tmpName:=tmp^.Name;

i:=1;

{ищем tmpName в правых или левых}

If tmp<>Nil Then Seek(tmpName,ListLR,tmp);

{tmp указывает на элемент с которого нужно начать добавлять}

inf2.Name:=tmpName;

While (tmp<>Nil) and (tmp^.Name<>#0) Do

Begin

inf.Name:=tmp^.Name;{!!! нужно проверить на повторяющиеся!!!}

If SearchInBlock(y,ListLR,inf)=0 Then

InsListInBlock(y,ListLR,inf2,inf);

tmp:=tmp^.Next;

End;

Until p=Nil;

End;

Var tmp:List;

term:String;

Label More,Next;

Begin

{предполагаем что грамматика не содержит ошибок}

{анализ грамматики без отслеживания ошибок}

y:=1;

i:=1;

Repeat

PosStr(y,s);

Blank;

i:=Pos('=',S)+1;{i ставим после:=}

More:Blank;

If s[i]='<' Then

Begin

inc(i);

Blank;

Terminal(term);

tmp.Name:='<'+term+'>';

If (SearchInBlock(y,LTN,tmp)=0) and (term>'') Then

Complete(LTN,tmp);{добавляем левый}

Blank;

inc(i);

End

Else

Begin

Terminal(term);

tmp.Name:=term;

If (SearchInBlock(y,LTN,tmp)=0) and (term>'') Then

Complete(LTN,tmp);{добавляем левый}

If (i-1)=Len Then {после:= или после | только один терминал}

Complete(RTN,tmp);

End;

If i>Len Then Goto Next;{последний в строке был терминал}

While (i<Len) and (S[i+1]<>'|') Do inc(i);{до конца правила}

If s[i]='>' Then {последний в правиле нетерминал}

Begin

While (i>1) and (s[i]<>'<') Do dec(i);

inc(i);

Blank;

Terminal(term);{последний нетерминал}

tmp.Name:='<'+term+'>';

If (SearchInBlock(y,RTN,tmp)=0) and (term>'') Then

Complete(RTN,tmp);{добавляем правый}

inc(i);{пропуск >}

If s[i]='|' Then

Begin

inc(i);

Goto More;

End;

End

Else{последний в правиле терминал}

Begin

While (i>1) and not((s[i]=' ') or (s[i]='|') or (s[i]='>')) Do dec(i);

inc(i);

Blank;

Terminal(term);

tmp.Name:=term;

If (SearchInBlock(y,RTN,tmp)=0) and (term>'') Then

Complete(RTN,tmp);{добавляем правый}

If s[i]='|' Then

Begin

inc(i);

Goto More;

End;

End;

If i<Len Then{прошли не всю строку}

Goto More;

next:inc(y);

tmp.Name:=#0;{после каждой строки ставим разделитель}

Complete(LTN,tmp);{добавляем левый}

Complete(RTN,tmp);{добавляем правый}

Until y>CLine;

{после цикла получили "предварительные" левые и правые, их еще надо дополнить}

For y:=1 To 10 Do

Begin

Add_(LTn);

Add_(RTn);

End;

{получили левые и правые, разделенные #0}

End;

Procedure Matrix;

Procedure Precede;

Label More,Next;

Var mi,mj:Byte;

tmp:List;

p:NotTerm;

term,term2:String;

Ex:Boolean;

Begin

y:=1;

i:=1;

Repeat

PosStr(y,s);

Blank;

i:=Pos('=',S)+1;{i ставим после:=}

More:Blank;

If s[i]='<' Then

Begin

inc(i);

Blank;

Terminal(term);

tmp.Name:='<'+term+'>';

term2:=tmp.Name;

Blank;

inc(i);

mi:=Search(Trm_notTrm,tmp);

If Terminal(term) Then{нетерминал за ним терминал}

Begin

tmp.Name:=term;

mj:=Search(Trm_notTrm,tmp);

Ex:=matrixprecede[mi,mj]=0;

If not Ex Then

matrixprecede[mi,mj]:=4

Else

matrixprecede[mi,mj]:=3;

p:=RTN;

Seek(term2,RTN,p);

While (p<>Nil) and (p^.Name<>#0) Do

Begin

tmp.Name:=p^.Name;

mi:=Search(Trm_notTrm,tmp);

Ex:=matrixprecede[mi,mj]=0;

If not Ex Then

matrixprecede[mi,mj]:=4

Else

matrixprecede[mi,mj]:=2;

p:=p^.Next;

End;

End

Else

If i>Len Then Goto Next

Else

If s[i]='|' Then

Begin

inc(i);

Goto More;

End;

Blank;

If s[i]='|' Then

Begin

inc(i);

Goto More;

End;

If i<=Len Then{не дошли до конца правила}

Begin

i:=i-Length(term);

While s[i]=' ' Do dec(i);

Goto More;

End;

End

Else

Begin

Terminal(term);

tmp.Name:=term;

mi:=Search(Trm_notTrm,tmp);

Blank;

If i>Len Then{последний в правиле терминал}

Goto Next;

If s[i]='<' Then{за терминалом следует нетерминал}

Begin

inc(i);

Terminal(term);

tmp.Name:='<'+term+'>';

mj:=Search(Trm_notTrm,tmp);

{записываем в матрицу =}

Ex:=matrixprecede[mi,mj]=0;

If not Ex Then

matrixprecede[mi,mj]:=4

Else

matrixprecede[mi,mj]:=3;

p:=LTN;

Seek(tmp.Name,LTN,p);

While (p<>Nil) and (p^.Name<>#0) Do

Begin

tmp.Name:=p^.Name;

mj:=Search(Trm_notTrm,tmp);

Ex:=matrixprecede[mi,mj]=0;

If not Ex Then

matrixprecede[mi,mj]:=4

Else

matrixprecede[mi,mj]:=1;

p:=p^.Next;

End;

Blank;

inc(i);

Blank;

If s[i]='|' Then

Begin

inc(i);

Goto More;

End;

If i<=Len Then{не дошли до конца правила}

Begin

i:=i-Length(term)-2;

Goto More;

End;

End

Else

If i<Len Then

Begin

If s[i]='|' Then

Begin

inc(i);

Goto More;

End;

{за терминалом терминал}

tmp.Name:=term;

mi:=Search(Trm_notTrm,tmp);

Terminal(term);

tmp.Name:=term;

mj:=Search(Trm_notTrm,tmp);

Ex:=matrixprecede[mi,mj]=0;

If not Ex Then

matrixprecede[mi,mj]:=4

Else

matrixprecede[mi,mj]:=3;

i:=i-Length(term);

End;

End;

If i<Len Then{прошли не всю строку}

Goto More;

next:inc(y);

Until y>CLine;

End;

Procedure WrtSymbol(i,j,c:Byte);

Begin

Case c of

1:Begin

OutTextXY(18+i*25,27+j*24-40,'<');

PutPixel(18+i*25+5,27+j*24+3-40,3);

End;

2:Begin

OutTextXY(18+i*25,27+j*24-40,'>');

PutPixel(18+i*25-1,27+j*24+3-40,3);

End;

3:Begin

OutTextXY(18+i*25,25+j*24+3-40,'=');

PutPixel(18+i*25+2,25+j*24+3-40,3);

End;

4:OutTextXY(18+i*25,25+j*24+3-40,'X');

End;

End;

Var sdig:String[2];

j:Byte;

x,y:Byte;

tmp:NotTerm;

tmp2:NotTerm;

Error:Boolean;

Pic:Pointer;

size:Word;

Begin

Message(30,15,15,7,'',False);

Zoom;

Message(30,15,15,7,'Матрица предшествования',False);

Tab(CTrmNotTrm+1,10,20);

WriteGr('ГРАММАТИКА',440,360,200);

For j:=1 To CLine Do

Begin

PosStr(j,s);

LineStr(s,400,375+j*13);

End;

TextColor(14);

TextBackGround(0);

Window(1,1,80,28);

x:=2;

y:=24;

GotoXY(50,2);

WriteLN('Левые Правые');

SetColor(14);

tmp:=Trm_NotTrm;

tmp2:=notTerminalL;

For i:=1 To CTrmNotTrm Do

Begin

Str(i,sdig);

OutTextXY(18+i*25,25,sdig);

OutTextXY(18,35+i*24,sdig);

inc(y);

If y=29 Then

Begin

inc(x,13);

y:=25;

End;

GotoXY(x,y);

TextColor(14);

Write(sdig,'. ');

TextColor(3);

Write(tmp^.Name);

GotoXY(43,2+i);

If tmp2<>Nil Then

Write(tmp2^.Name);

tmp2:=tmp2^.Next;

tmp:=tmp^.Next;

End;

tmp2:=LTN;

i:=3;

GotoXY(50,WhereY);

While tmp2<>Nil Do

Begin

If tmp2^.Name=#0 Then

Begin

GotoXY(50,WhereY);

inc(i);

End;

GotoXY(WhereX,i);

If tmp2^.Name<>#0 Then Write(tmp2^.Name);

tmp2:=tmp2^.Next;

End;

tmp2:=RTN;

i:=3;

GotoXY(70,WhereY);

While tmp2<>Nil Do

Begin

If tmp2^.Name=#0 Then

Begin

GotoXY(70,WhereY);

inc(i);

End;

GotoXY(WhereX,i);

If tmp2^.Name<>#0 Then Write(tmp2^.Name);

tmp2:=tmp2^.Next;

End;

Precede;

SetColor(3);

Error:=False;

For j:=1 To CTrmNotTrm Do{!!!}

For i:=1 To CTrmNotTrm Do{!!!}

Begin

If MatrixPrecede[j,i]=4 Then Error:=True;

WrtSymbol(i,j+2,MatrixPrecede[j,i]);

End;

If Error Then

Begin

TextColor(15);

TextBackGround(1);

Message(30,15,15,7,'Нажмите любую клавишу',True);

VerticalRetrace;

SaveWindow(GraphCooX(20),GraphCooY(12),GraphCooX(62)+1,GraphCooY(19),Pic,size);

TextBackGround(4);

TextColor(14);

OpenWindow(20,12,60,17,3,' Внимание ',True);

WriteLn('Матрица предшествования содержит ошибки');

Write(' Построение функции предшествования ');

Write(' невозможно');

Attention(363,243);

ReadKey;

LoadWindow(GraphCooX(20),GraphCooY(12),size,pic);

End;

End;

{основная программа}

Begin

Init;

InitText;

If InputText Then

Begin

Check;

SearchLR;

Matrix;

ClearBuf;

ReadKey;

End;

GraphWriteOff;

CloseGraph;

End.



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2020-03-31 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: