#include <stdio.h>
#include <dos.h>
#include <conio.h>
#define TYP unsigned char //Typ von Bändern
#define MAXRK 500 //maximale RekursionsTiefe
void tut(){sound(500);delay(20);nosound();}
void fehler(char d);
char open(char *c);
char readln(TYP lin[1051],int *z);
void inread(TYP ein[50],TYP t_n[256][22],TYP lin[1051]);
void first(int pos,TYP ein[300][50],TYP aus[101]);
void follo(TYP nt,TYP ein[300][50],TYP aus[101]);
void beschreibung(void);
//****************** G L O B A L E V A R I A B L E N **********************
FILE *tx1,*tx2; //DateiZeiger
int RK =0; //RekursionsTiefe
int Z_E =0; //Ende der Regel-Zeilen
int ZL =0; //ZeilenZähler
//***************************************************************************
//************************* M A I N T E I L *********************************
//***************************************************************************
void main(int k,char *NAME[]){
TYP ein[300][50]; //Regel-Matrix-Eingabe
TYP ein_tmp[50]; //Regel-Matrix-temporär
TYP aus[300][101]; //Ausgegebene TerminalSymbole
TYP t_n[256][22]; //NamensListe der TerminalSymbole
TYP lin[21*50+1]; //Einspeicherung der gesäuberten RegelZeile
int z_m[300]; //Merker der ZeilenNummer
int lv1,lv2,lv3; //LaufVar
char err=0; //ErrorCode
if(k!=2) {beschreibung();return;} //ES wurde keine Datei angegeben
//****************** DateiÖffnen und Vorbereiten der Felder *****************
if((err=open(*(NAME+1)))!=0) {fehler(err);return;} // 1..7
for(lv1=0;lv1<300;lv1++) for(lv2=0;lv2<50 ;lv2++) ein[lv1][lv2]=255;
for(lv1=0;lv1<300;lv1++) for(lv2=0;lv2<101;lv2++) aus[lv1][lv2]=0;
for(lv1=0;lv1<256;lv1++) for(lv2=0;lv2<22 ;lv2++) t_n[lv1][lv2]=0;
t_n[0][0]='\'';t_n[0][1]='\''; //default
//*************** Einlesen der RegelZeilen in EingabeMatrix *****************
clrscr();printf("\r"); //BildSchirm vorbereiten
do{lv1=0; //lv1=merker für SymbolZahl
err=readln(lin,&lv1); //Auslesen einer Zeile aus .ll1
if(lv1==0 && err==99)continue; //ein Typisches Ende erreicht
if(lv1<3 && err==0)err=6; //ist 'NT - ..' verletzt wurden
if(err==0 && Z_E==300){Z_E=301;continue;} //Ende Überschritten
if(err<9 && err>0) {fehler(err+6);printf("%d",ZL);return;} //7..14
z_m[Z_E]=ZL; //Notieren der ZeilenNummer
inread(ein[Z_E],t_n,lin); //Einlesen in Regel-Matrix
printf("gelesen %d R%d:= %s\n",z_m[Z_E],Z_E,lin); //Ausgabe der ZeilenNummer
++Z_E; //ZeilenAnzahl anpassen
}while(err==0 && Z_E!=301); //Ende des Einlesens
if(Z_E==0)fehler(15);if(Z_E==301)fehler(16);//Fehler ZeilenZahl
//************ Kontrolle auf doppelte Zeilen und LinksRekursion *************
for(lv1=0;lv1<Z_E && ein[lv1][0]!=ein[lv1][1];lv1++); //LinksRekursion ?
if(lv1<Z_E){fehler(20); //FehlerAusgabe
printf("%d\n\n\tBestätige mit E N T E R!!\n\n",z_m[lv1]);
while(getch()!=13);while(kbhit()) err=getch();} //LinksRekursion ?
for(lv1=0,err=0;lv1<Z_E-1 && err<50; lv1++) //Doppelte Zeilen
for(lv2=lv1+1; lv2<Z_E && err<50;lv2++) //Doppelte Zeilen
for(err=0,lv3=0;lv3<50; lv3++) if(ein[lv1][lv3]==ein[lv2][lv3]) err++;
if(err==50){fehler(19); //FehlerAusgabe
printf("%d mit %d\n",z_m[lv1-1],z_m[lv2-1]);
printf("\tWenn Scanner hängt, kannst Du mit TasteDruck abbrechen!\n");
printf("\n\tBestätige mit E N T E R!!\n");
while(getch()!=13);while(kbhit()) err=getch();} //LinksRekursion ?
//********************** Suche nach Abdeckungen der Regeln ******************
while(kbhit()) lv1=getch(); //TastenPuffer Leeren
for(lv1=0;lv1<Z_E;lv1++){ //alle Regeln
RK=0; //Globalen Zähler Rücksetzen
printf("R%d von %d",lv1,Z_E-1); //Ausgabe der Regel
for(lv2=0;lv2<50;lv2++) ein_tmp[lv2]=ein[lv1][lv2];//copy
lv3=0; //
do{
first(lv1,ein,aus[lv1]); //Such die Menge
if(aus[lv1][0]==0)lv3=1; //kein follow award
if(aus[lv1][0]==1){
aus[lv1][0]=0; //rücksetzen
if(ein[lv1][1]==0){lv3=2;continue;} //für A->''
if(ein[lv1][2]<100){aus[lv1][ein[lv1][2]]=1;lv3=1;continue;}//Terminal found;Regist
if(ein[lv1][2]>100){for(lv2=1;lv2<49;lv2++)
ein[lv1][lv2]=ein[lv1][lv2+1]; //Kürzen
ein[lv1][49]=255;}
if(ein[lv1][1]==255) {lv3=2;}}
}while(lv3==0);
for(lv2=0;lv2<50;lv2++) ein[lv1][lv2]=ein_tmp[lv2];//recopy
if(lv3==2)follo(ein[lv1][0],ein,aus[lv1]); //FollowAufruf
if(!kbhit()) printf(" beendet..\n"); //BenutzerAbb
if(kbhit() ){printf(" nicht beendet..\n"); //BenutzerAbb
fehler(18);fclose(tx1);fclose(tx2);return;}//Fehler
if(RK>=MAXRK) {fehler(17);fclose(tx1);fclose(tx2);return;}}
//********************** Ausgabe der Abdeckungen ****************************
for(lv2=0;lv2<Z_E;lv2++){ //Über alle Regeln
fprintf(tx2,"%s -> ",t_n[ein[lv2][0]]); //Ausgabe der Regel
for(lv1=1;ein[lv2][lv1]!=255 && lv1<50; //Ausgabe der Regel
fprintf(tx2,"%s",t_n[ein[lv2][lv1++]])); //Ausgabe der Regel
fprintf(tx2,"\r\n;** ABDECKUNG FÜR ** R%d:= { ",lv2);//RegelNummer schreiben
for(lv1=0,lv3=0;lv1<101;lv1++){ //Über alle T-Spalten
if(aus[lv2][lv1]==1)lv3++;}
for(lv1=0,err=0;lv1<100;lv1++){ //Über alle T-Spalten
if(aus[lv2][lv1]==1 && lv3==1){fprintf(tx2,"%s }",t_n[lv1]);err++;}
if(aus[lv2][lv1]==1 && lv3>1){fprintf(tx2,"%s, ",t_n[lv1]);err++;lv3--;}}
if(aus[lv2][100]==1) {fprintf(tx2,"'$' }");err++;}
if(err==0)fprintf(tx2,"Keine Terminals für diese Regel! }");
fprintf(tx2,"\r\n");} //ZeilenUmbruch
//******* Suche nach gleichen Abdeckungen für gleiche NichTerminals *********
for(lv1=0; lv1<Z_E-1 ;lv1++){ //Abdeckung
for(lv2=lv1+1; lv2<Z_E ;lv2++){ //Abdeckung
for(lv3=0,err=0;lv3<101 ;lv3++){ //Abdeckung
if(aus[lv1][lv3]==1 && aus[lv2][lv3]==1 && //Abdeckung
ein[lv1][0]==ein[lv2][0]) err=1;} //Abdeckung
if(err==1){fehler(21); //FehlerAusgabe
printf("\n\tBetroffen ist Regel %d und %d ",lv1,lv2);//
fprintf(tx2,"\r\n;\tDoppelte Abdeckung für Regel %d und %d",lv1,lv2);//
printf("in den Zeilen %d und %d",z_m[lv1],z_m[lv2]);//
printf("\n\tBestätige mit E N T E R!!");
while((err=getch())!=13);while(kbhit()) err=getch();err=1;}}} //Abdeckung
fclose(tx1);fclose(tx2);}
//***************************************************************************
//* HUP1 **** F E H L E R A U S G A B E *************************************
//***************************************************************************
void fehler(char d){
char *ff[23]={
/* 0*/"\t\t A L L E S O K ! !",
/* 1*/"\t\tDer Dateiname ist zu lang!",
/* 2*/"\t\tDer Dateiname hat ein ungültiges Format!",
/* 3*/"\tDer Dateiname hat eine ungültige ErweiterungsBezeichnung!",
/* 3*/"\tDie zu schreibende Datei existiert bereits!\n"
/* 4*/"\tLösche diese Datei erst oder nimm einen anderen Namen!",
/* 5*/"\tKonnte die von Dir angegebene Datei nicht schreiben bzw. öffnen!!",
/* 6*/"\tKonnte die von Dir angegebene Datei nicht finden bzw. öffnen!!",
/* 7*/"\tZeilenBeginnFehler in Zeile: ",
/* 8*/"\tRem-ZeilenFehler in Zeile: ",
/* 9*/"\tSpace-ZeilenFehler in Zeile: ",
/*10*/"\tNichTerminalZeichenFehler in Zeile: ",
/*11*/"\tTerminalZeichenFehler in der Zeile: ",
/*12*/"\tVerletzung der Bedingung 'Nichtterminal -> ...' in der Zeile: ",
/*13*/"\tName eines Symbols zu lang in Zeile: ",
/*14*/"\tZu viele Symbole in einer Zeile, in Zeile: ",
/*15*/"\tkeine Zeile vorhanden mit GrammatikAusdruck.",
/*16*/"\tZu viele Zeilen mit GrammatikAusdrücken in dieser Datei.",
/*17*/"\tDie Rekursionstiefe ist zu groß für dieses Programm!!!",
/*18*/"\tDurch Benutzer abgebrochen",
/*19*/"\tM ö g l i c h e E n d l o s S c h l e i f e ! !\n"
/*19*/"\tFolgende Zeilen sind doppelt vorhanden: ",
/*20*/"\tKeine LL1-Grammatik - LinksRekursion in Zeile ",
/*21*/"\tWarnung keine LL1-Grammatik, Schnittmenge nich Null",
/*? */"\t ************** ENDE ***********"};
tut();printf("\n\n%s",ff[d]);}
//***************************************************************************
//* HUP2 **** D A T E I E N Ö F F N E N ***********************************
//***************************************************************************
char open(char *c){
int lv1,lv2; //Laufvariablen
char dat1[13]; //AusLeseDateiName
char dat2[13]; //SchreibDateiName
for(lv1=0;lv1<12;lv1++) dat1[lv1]=dat2[lv1]='\0'; //Löschen des Inhalts
lv2=0;while(*c!='\0' && lv2<13){ //Einlesen des DateiNamens in dat1/2
*(dat1+lv2)=*(dat2+(lv2++))=*(c++);} //Anpassen der Zeiger...
if(lv2==13)return(1); //DateiName ist länger als 12 Zeichen
if(lv2 <5 ) return(2); //min ist 1.123
lv1=0;c=dat1; //Anpassen der Kontrolleparameter
while(*(c++)!='.' && (lv1++)<9); //Suche den Punkt
if((lv2-lv1!=4 ) || //nur eine ERW und genau 3 Zeichen
(*(c+0)!='l' && *(c+0)!='L') || //1Buchstabe groß und klein
(*(c+1)!='l' && *(c+1)!='L') || //... 3Buchstabe aus Symetriegrund
(*(c+2)!='1' && *(c+2)!='1'))return(3);//ist ERW !='ll1'
*(dat2+lv1+3)='$'; //SchreibDateiName bestimmen
if((tx2=fopen(dat2,"rb"))!=NULL){
tut();printf("\r\n\tDiese Datei '%s' existiert bereits!\r\n",dat2);
printf("\tÜberschreiben J/N?: J");
do{
lv1=getch();
if( (lv1!='j')&&(lv1!='J')&&
(lv1!='n')&&(lv1!='N')&&
(lv1!=27 )&&(lv1!=13 )) {tut();}
//Falsche Taste gedrückt
}while((lv1!='j')&&(lv1!='J')&&
(lv1!='n')&&(lv1!='N')&&
(lv1!=27 )&&(lv1!=13 ));
fclose(tx2);
if((lv1=='n')||(lv1=='N')||(lv1==27)) return(4);} //Nicht Überschreiben
if((tx1=fopen(dat1,"rb"))==NULL)return(6);//LESE-DATEI Öffnen
if((tx2=fopen(dat2,"wb"))==NULL)return(5);//LESE-DATEI Öffnen
return(0);}
//***************************************************************************
//* HUP3 **** L E S E N E I N E R R E G E L Z E I L E *******************
//***************************************************************************
char readln(TYP lin[1051],int *z){
int x=0; //Anzahl der Buchstaben in einem T oder NT
int l=0; //Zähler der Buchstaben in einer Line
TYP c; //Byte zum Auslesen der Zeichen aus einer Datei
//****************************** ZeilenBeginn *******************************
START: ZL++; //eine neue Zeile hat begonnen
c=fgetc(tx1);if(feof(tx1)) goto ENDE2; //hole Zeichen aus Quelle
if(c==';') {goto REMLN;} //Remline gefunden
if(c==' ') {goto SPACE;} //Leerzeichen
if(c=='<') {lin[l++]=c;x=0;(*z)++;goto NICHT;}//Beginn eines NT
if(c=='\'') {lin[l++]=c;x=0;(*z)++;goto TERMI;}//Beginn eines T
return(1); //sonst Fehler Zeilenbeginn
//******************************* REM - Line ********************************
REMLN: c=fgetc(tx1);if(feof(tx1)) goto ENDE2; //Hole Zeichen
if(c==13){ //ist Return erreicht
c=fgetc(tx1);if(feof(tx1))goto ENDE2;//Hole Zeichen
if(c==10)goto START; //search for Carrige
return(2);} //ansonsten Fehler REMline
goto REMLN; //alles >ok< weiter in REMline
//********************* LeerBereich und ZeilenEnde **************************
SPACE: if((*z)==51)return(8); //zu viele Symbole in Zeile
c=fgetc(tx1);if(feof(tx1)) goto ENDE2; //Hole Zeichen
if(c==13){ //ist Return erreicht
c=fgetc(tx1);if(feof(tx1))goto ENDE2;//Hole Zeichen
if(c==10)goto ENDE1; //search for Carrige
return(3);} //ansonsten Fehler SPACEline
if(c==' ') goto SPACE; //alles >ok< weiter in REMline
if(c=='-' && (*z)==1) {
c=fgetc(tx1);if(feof(tx1)) return(6);//Verletzung 'NT -> ...'
if(c!='>') return(6);
(*z)++;goto SPACE;} //
if(c=='<') {lin[l++]=c;x=0;(*z)++;goto NICHT;}//Beginn eines NT
if(c=='\'') {lin[l++]=c;x=0;(*z)++;goto TERMI;}//Beginn eines T
return(3); //ansonsten Fehler SPACEline
//****************************** NichtTerminal ******************************
NICHT: if((*z)==2)return(6); //Fehler 2*NT am Anfang erkannt
c=fgetc(tx1);if(feof(tx1)) return(4); //Hole Zeichen
if((c=='>' && x==0) || //leerer NT?
(c< ' ' && c!='§')|| //Fehlerhafte Zeichen?
(c=='<')||(c=='$')|| //Fehlerhafte Zeichen?
(c=='\'')) return(4); //Fehlerhafte Zeichen?
if(c=='>') {lin[l++]=c;goto SPACE;} //Ende eines NT?
if(++x==20)return(7); //NT-Name uzu lang
lin[l++]=c;goto NICHT; //Eintrag Zeichen und weiter
//******************************** Terminal *********************************
TERMI: if((*z)==1 || (*z)==2)return(6); //Folge "NT -" ist verletzt
c=fgetc(tx1);if(feof(tx1)) return(5); //Hole Zeichen
if((c< ' ' && c!='§')|| //Fehlerhafte Zeichen?
(c=='$')|| //Fehlerhafte Zeichen?
(c=='<')||(c=='>')) return(5); //Fehlerhafte Zeichen?
if(c=='\'') {lin[l++]=c;goto SPACE;} //Ende eines T?
if(++x==20)return(7); //T-Name zu lang
lin[l++]=c;goto TERMI; //Eintrag Zeichen und weiter
//********************* Ende einer Ein-Zeile ********************************
ENDE1: lin[l]='\0';return(0); //Normales Ende
ENDE2: lin[l]='\0';return(99);} //Absolutes Ende
//***************************************************************************
//* HUP4 **** E I N F E L D E I N L E S E N *******************************
//***************************************************************************
void inread(TYP ein[50],TYP t_n[256][22],TYP lin[1051]){
static TYP Z_T =1; //Zähler der Terminal-Symbole; default epsilon=n_t[0]
static TYP Z_N =0; //Zähler der Nicht-Terminal-Symbole
TYP zein=0; //Zeiger auf Pos in Ein
int pl=0; //Zeiger auf Pos in Line
TYP nam[22]; //NamensMerker
TYP t_nt; //Merker ob Term oder NichTerm
TYP lv,lv1,merk; //LaufVar
for(pl=0;lin[pl]!='\0';){ //ganze Line Durchsuchen
for(lv=0;lv<22;lv++) nam[lv]='\0';//NamensFeld leeren
t_nt=1;if(lin[pl]=='<')t_nt=0; //Beginn eines NT oder T
nam[0]=lin[pl++]; //Eintrag des T || NT's
for(lv=1;lin[pl]!='>' && lin[pl]!='\''; nam[lv++]=lin[pl++]);//des Symbols aus Line
nam[lv]=lin[pl++]; //Eintrag von ' oder >
//************************* NichtTerminalSymbol **************************
if(t_nt==0){ //Eintrag des NichtTerminals
for(lv=0,merk=0;lv<=Z_N && merk!=22;lv++){//Suche NT in Symbol-Liste
for(lv1=0,merk=0;lv1<22;lv1++) //Vergleiche Buchst
if(nam[lv1]==t_n[lv+128][lv1]) merk++;}//wenn Bchst gefunden
if(lv==Z_N+1){ //falls Neuer Eintrag eines NT
for(lv1=0;lv1<22;lv1++) //Alle Buchstaben in SymbolListe
t_n[Z_N+128][lv1]=nam[lv1];Z_N++;} //Eintrag des Symbols
ein[zein++]=lv+127;} //Eintrag des NT in RegelBand
//************************** TerminalSymbol ******************************
if(t_nt==1){ //Eintrag des NichtTerminals
for(lv=0,merk=0;lv<=Z_T && merk!=22;lv++){//Suche T in Symbol-Liste
for(lv1=0,merk=0;lv1<22;lv1++) //Vergleiche Buchst
if(nam[lv1]==t_n[lv][lv1]) merk++;}//wenn Bchst gefunden
if(lv==Z_T+1){ //Neuer Eintrag eines T
for(lv1=0;lv1<22;lv1++) //Alle Buchstaben
t_n[Z_T][lv1]=nam[lv1];Z_T++;} //Eintrag des Symbols
ein[zein++]=lv-1;}}} //Eintrag eines T in EinBand
//***************************************************************************
//* HUP5 **** Suche des First-Terminals *************************************
//***************************************************************************
void first(int pos,TYP ein[300][50],TYP aus[101]){
TYP t=ein[pos][1]; //Zuweisung First der rechten RegelSeite
int lv; //LaufVariable
if(kbhit()) return; //BenutzerAbbruch
if(t==0) {aus[0]=1;return;} //Follow erwartet zurück
if(t<100){aus[t]=1;return;} //Terminal found;Registriere in Ausgabe
for(lv=0;lv<Z_E && RK<MAXRK;lv++){//das NT suchen im Regelfeld
if(ein[lv][0]==t){RK++; //habe NT gefunden
first(lv,ein,aus);RK--;}}} //suche das First dieses NT's
//***************************************************************************
//* HUP6 **** Suche des Follow-Terminals ************************************
//***************************************************************************
void follo(TYP nt,TYP ein[300][50],TYP aus[101]){
int lv,l1,ps;
if(kbhit()) return; //BenutzerAbbruch
for(lv=0;lv<Z_E && RK<MAXRK;lv++){ //Suche NT in allen RegelZeilen
for(ps=1;ein[lv][ps]!=255 || ps>50;ps++){ //NT in rechten RegelZeichen
if(ein[lv][ps]==nt){ //NT ist gefunden
if(ein[lv][ps+1]<100){ //Follow ist ein Terminal
aus[ein[lv][ps+1]]=1;continue;} //Eintrag und Tschüß
if(ein[lv][ps+1]==255 && nt!=ein[lv][0]){//Follow ist '$'
aus[100]=1;RK++; //Eintrag und Follow auch des
follo(ein[lv][0],ein,aus);RK--;continue;}//NT von linke RegelSeite
if(ein[lv][ps+1]>127){ //Follow ist auch ein NT
for(l1=0;l1<Z_E && RK<MAXRK; l1++){ //dann alle First's von
if(ein[lv][ps+1]==ein[l1][0]){ //diesem NT
RK++;first(l1,ein,aus);
if(aus[0]==1){
aus[0]=0; //rücksetzen
follo(ein[l1][0],ein,aus);}
RK--;}}}}}}}
//***************************************************************************
//* HUP7 ******************** Hilfe Menu ************************************
//***************************************************************************
#define ZZ 92 //Maximale ZeilenZahl des BeschreibungsTextes /
void beschreibung(void){
char *text[ZZ]={
"i---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---©", //LL 1
"¦ ¦", //LL 2
"¦ ----+ +---+ -- - +---+ +---+ -- - +--+ + ¦",//LL 3
"¦ +¦ ¦ ++--¦ ++--+ ++- +---+ +¦ ¦ +¦ ¦ ¦ ¦", //LL 4
"¦ ----+ ++ + +-+ +---+ +---+ ----+ ++ +-+ ¦",//LL 5
"¦ ¦", //LL 6
"ã---------------------------------------------------------------Á",//LL 7
"¦ ¦", //LL 8
"¦ -+ -+ -- +---+ ----+ +---+ +--+ ++--+ + +---++---+ ¦", //LL 9
"¦ +¦ +¦ +¦ -- +---+ +¦ ++--¦ +¦ ¦ ¦+¦ ¦ ¦ ++- ++--+ ¦", //LL*10*
"¦ ----+----+-- +---+ ----+ ++ + ++ +-+++ +-+ +---+++ + ¦",//LL 1
"¦ ¦", //LL 2
"ã---------------------------------------------------------------Á",//LL 3
"¦ ¦", //LL 4
"¦ ----+ -- +---+ +---+ +-- ¦", //LL 5
"¦ +¦ +¦ +--+¦ +--+¦ +---+ ¦", //LL 6
"¦ ----+ -- +---+ +---+ +---+ ¦", //LL 7
"¦ ¦", //LL 8
"È---  ---  ---  ---  ---  ---  ---  ---  ---  ---  ---¥", //LL 9
" ", //LL*20*
"i---------------------------------------------------------------©",//LL 1
"ã-------------- KURZE EINLEITUNG ZUR GRAMMATIK LL1 -------------Á", //LL 2
"È---------------------------------------------------------------¥",//LL 3
" ", //LL 4
"Eine LL1-Grammatik ist eine vereinfachte Kontextfreie-Grammatik.", //LL 5
"Eine LL1-Grammatik kann zur Syntaxanalyse von Programmiersprachen", //LL 6
"verwendet werden (einfache deterministische Top - Down- Methode).", //LL 7
"L L 1 - Grammatik", //LL 8
"¦ ¦ ¦", //LL 9
"¦ ¦ +-- von der Eingabe wird jeweils EIN Symbol ausgewertet", //LL*30*
"¦ +---- Analyse von Links nach Rechts", //LL 1
"+------ Entscheidung nach dem am weitesten links stehenden", //LL 2
" TerminalSymbol", //LL 3
" ", //LL 4
"i---------------------------------------------------------------©",//LL 5
"ã---------- REGELN UND EINSCHRÄNKUNG ZUR LL1 GRAMMATIK ---------Á", //LL 6
"È---------------------------------------------------------------¥",//LL 7
" ", //LL 8
"Auf der linken Regelseite muß genau ein NichTerminalSymbol (NT)", //LL 9
"stehen. Auf der rechten Seite können Terminals und NichTerminals", //LL*40*
"wild durcheinander sein. Sind die NT- Symbole der linken Regel-", //LL 1
"seite identisch, so muß die Schnittmenge der Beschreibungsmengen", //LL 2
"der einzelnen Regeln unterschiedlich sein, d.h. beispielsweise", //LL 3
"R1:= -> (c)(f)", //LL 4
"R2:= -> (c) Terminal 'c' ist Schnittmenge aus R1 und R2,", //LL 5
"und das ist unzulässig, da die LL1- Grammatik nicht in der Lage", //LL 6
"ist zwischen R1 und R2 zu entscheiden, welch der Grammatikregel", //LL 7
"zu nehmen ist. Weiterhin ist eine LL1-Grammatik nicht in der Lage", //LL 8
"links Rekursive Ausdrücke zu verarbeiten.", //LL 9
" ", //LL*50*
"i---------------------------------------------------------------©", //LL 1
"ã-------- WAS MACHT DER SCANNER MIT DER LL1 GRAMMATIK ? --------Á", //LL 2
"È---------------------------------------------------------------¥", //LL 3
" ", //LL 4
"Mit dem Scanner werden die einzelnen Regeln der Grammatik durch-", //LL 5
"gekämmt, es wird bestimmt, welche Terminals mit der einzelnen", //LL 6
"Regel abgedeckt werden. z.B.", //LL 7
" ", //LL 8
"R1:= -> (ab) ¦ (ab) -+", //LL 9
"R2:= -> ¦ (k)(h) ¦", //LL*60*
"R3:= -> (k) ¦ (k) +-- abgedeckte Menge", //LL 1
"R4:= -> (h) ¦ (h) -+", //LL 2
"i---------------------------------------------------------------©", //LL 3
"ã---------------------------------------------------------------Á", //LL 4
"ã------ FUNKTIONSWEISEN UND EINSCHRÄNKUNGEN ZUM PROGRAMM -------Á", //LL 5
"ã---------------------------------------------------------------Á", //LL 6
"È---------------------------------------------------------------¥", //LL 7
"Hinter dem Programmnamen des Scanners muß eine Datei mit der Er-", //LL 8
"weiterung ll1 stehen (z.B. C:\\>Scanner.exe gramatik.ll1). Das", //LL 9
"Programm ist in der Lage, 100 Terminal & 100 NichterminalSymbole", //LL*70*
"zu verarbeiten. TerminalSymbole werden in runden und Nichttermi-", //LL 1
"nalSymbole werden in eckige Klammern geschrieben. Namen für ein", //LL 2
"Terminal bzw. NichtTerminal dürfen maximal 19 Zeichen lang sein.", //LL 3
"Zulässige Buchstaben für Namen: alle Zeichen außer <>, () und die", //LL 4
"ASCII-Zeichen mit der Nummer unterhalb von 32 außer '§'. Zwischen", //LL 5
"Groß- und Kleinbuchstaben wird unterschieden. Zwischen T und NT", //LL 6
"können beliebig viele FreiZeichen stehen. Für jede Regel muß eine", //LL 7
"neue Zeile begonnen werden. Ist eine neue Zeile genau am Anfang", //LL 8
"durch ein Semikolon eingeleitet, so wird diese Zeile als Komentar", //LL 9
"interpretiert und somit ignoriert. Es darf also auch keine Leer-", //LL*80*
"zeilen geben. Nach dem ersten NT muß ein Minus-Strich stehen. Das", //LL 1
"Epsilon ist als '()' zu schreiben. Das Programm ist in der Lage,", //LL 2
"eine LL1- Grammatik vom Umfang 300 Zeilen à 49 Symbole zu verar-", //LL 3
"beiten. Eine fertig verarbeitete Grammatik steht in der Datei", //LL 4
"gramatik.ll1 -> 'gramatik.ll$.' Hier noch ein Beispiel für eine", //LL 5
"Grammatik:", //LL 6
";****** eine Grammatik .....", //LL 7
" -> ", //LL 8
";******* ZwischenKomentar", //LL 9
" -> (^) (id) ", //LL*90*
" -> ()", //LL 1
";******* ENDE ***** ..."}; //LL 2
char tast,lv,akt=0,buffer[4000],x,y; //BildschirmPuffer
gettext(1,1,80,25,buffer);x=wherex();if((y=wherey()-1)==0) y=1;
textattr(102);window(1,1,80,25);clrscr(); //GesamtBildSchirm
textattr(30);window(4,3,76,23);clrscr(); //GesamtBildSchirm
//********************** Rand Malen ****************************************
cprintf(" +");for(lv=1;lv<70;lv++) cprintf("-");cprintf("+");//InnenRand1
for(lv=2;lv<21;lv++){gotoxy(2,lv);cprintf("¦");gotoxy(72,lv);cprintf("¦");} //InnenRand8
cprintf("\r\n +");for(lv=1;lv<70;lv++) cprintf("-");cprintf("+");//9.Zeile
//****************************** TastaturSteuerung *************************
do{textattr(27);window(8,4,72,22); //Einstellen des Fensters
while((inport(0x3da)&9)!=9);
clrscr();window(8,4,72,23); //Lösche TextSchirm
for(lv=0;lv<19;lv++){ //Ausgabe von 19 Zeilen
gotoxy(1,lv+1); cprintf("%s",text[lv+akt]);}
textattr(30);window(7,23,74,24); //untere InfoFeld
for(lv=0;lv<67;lv++) cprintf("-");
gotoxy(26,1);cprintf(" Zeilen %d - %d ",akt+1,akt+19);//ZeilenNummern
if(akt+19 <ZZ){gotoxy(57,1);cprintf("<< PgDn >>");} //PgDn-Info
if(akt >0 ){gotoxy(2 ,1);cprintf("<< PgUp >>");} //PgUp-Info
window(1,1,1,1); //Hide Cursor
TAST:tast=getch(); //Lese Taste
if(tast==0){tast=getch(); //SteurungsTaste Lesen
if(tast==80 && akt+19<ZZ){++akt;continue;} //go Down
if(tast==72 && akt>0 ){--akt;continue;} //go UP
if(tast==73 && akt>0 ){if((akt-=18)<0)akt=0; continue;}//PgDn
if(tast==81 && akt+19<ZZ){if((akt+=18)+19>ZZ)akt=ZZ-19;continue;}}//PgDn
if(tast!=27) {tut();goto TAST;} //Falsche Taste
}while(tast!=27);
textattr(7);
window(1,1,80,25);puttext(1,1,80,25,buffer);gotoxy(x,y);}//BildSchirm zurück
//***************************************************************************
//*************************** ENDE LL1 - SCANNER ****************************
//***************************************************************************
//****** p r o g r a m m i e r t v o n d a v e s u n i n 30h *******
//***************************************************************************
//************************** 16.06.1995 by Dave Sun *************************
//***************************************************************************
//***************************************************************************