Alter Code: LL1Parser

LL(k) Parser mit k=1 ist eins der einfachsten Parser für kontextfreie Grammatiken. Die Zahl k bedeutet die Symbole, die nach vorne geschaut werden, um zu entscheiden welche Regel zutrifft.

Die Grammatik wird dabei in der BNF beschrieben. Dabei gilt die Einschränkung, dass keine Linksrekursion erlaubt ist.

// written by André Betz 
// http://www.andrebetz.de

#include <stdio.h>
#include <stdlib.h>
#define  EPSILON '&'

/*
    LL(1)-Parser-Generator - keine Linksrekursion erlaubt
    A->AB; => 
    Umformen von EBNF -> BNF
    A->a(b)c => A->aBc,B->b
    A->a[b]c => A->aBc,B->b,B->&
    A->a{b}c => A->aBc,B->bB,B->&
    A->a|b   => A->a,A->b
    A->UV&   => A->UVX,X->&
*/

/* Baumstruktur */
typedef struct node
{
    struct node *suc;
    struct node *next;
    struct node *First;
    struct node *Follow;
    int            Nr;
    int            term;
    int            Epsfrei;
    char        sym;
    char        mark;
} *pnode;

/* erzeugt neuen Knoten */
pnode NewNode()
{
  pnode neu;
  char *point;
  int cnt;

  neu = (pnode)malloc(sizeof(struct node));
  point = (char*)neu;
  for(cnt=0;cnt<sizeof(struct node);cnt++)   {       point[cnt] = 0;   }   return neu; } /* schaut ob Zeichen im Baum schon vorhanden ist */ int isThere(pnode gram,char Sym) {     pnode HTrans = gram;     pnode Suc;     while(HTrans)     {         Suc = HTrans;         while(Suc)         {             if(Sym==Suc->sym) return 1;
            Suc = Suc->suc;
        }
        HTrans = HTrans->next;
    }
    return 0;
}

/* gibt Zeiger auf Element mit der Produktion zurück */
pnode getTransBegin(pnode gram,char Sym)
{
    pnode HTrans = gram;

    while(HTrans)
    {
        if(Sym==HTrans->sym) return HTrans;
        HTrans = HTrans->next;
    }
    return NULL;
}

/* gibt Zeiger auf Produktion in der sich das Symbol befindet */
pnode getTransInside(pnode suc,char Sym)
{
    pnode Suc = suc;

    while(Suc)
    {
        if(Sym==Suc->sym) return Suc;
        Suc = Suc->suc;
    }
    return NULL;
}

/* erzeugt aus der BNF-Grammatik einen Baum */
pnode Transform(char* Gram)
{
    pnode tree = NULL;
    pnode next;
    pnode help;
    pnode NTrans;
    int   GPtr = 0;
    int   NTr = 2;
    int      T = 0;
    int   NT = 0;
    char  Sym;

    while(Gram[GPtr]!=0)
    {
        Sym = Gram[GPtr];

        if(Sym!='=')
        {
            if(Sym!='.')
            {
                help = NewNode();

                if(Sym>='A'&&Sym<='Z')                 {                     help->Nr =NT;
                    if(!isThere(tree,Sym)) NT++;
                }
                else
                {
                    if(Sym!=EPSILON)
                    {
                          help->term = 1;
                        help->Nr = T;
                        if(!isThere(tree,Sym)) T++;
                    }
                    else 
                    {
                        help->term = 2;
                        Sym = 0;
                    }
                }
                help->sym     = Sym;

                switch(NTr) 
                {
                case 2:
                    tree   = help;
                    NTrans = help;
                    NTr = 0;
                    break;
                case 1:
                    NTrans->next = help;
                    NTrans = help;
                    NTr = 0;
                    break;
                default:
                    next->suc = help;
                    break;
                }
                next = help;
            }
            else NTr = 1;
        }
        GPtr++;
    }
    return tree;
}

/* untersucht auf Epsilonfreiheit */
void EpsilonTable(pnode Gram)
{
    pnode HTrans = Gram;
    pnode Suc;
    pnode help;
    int cntEps;
    int cntT;
    int cntNT;
    int cntSum;
    int cntFrei1;
    int cntNFrei1;
    int cntUnent1;
    int cntFrei2;
    int cntNFrei2;
    int cntUnent2;
    int Unent = 0;

    while(HTrans)
    {
        Suc = HTrans->suc;
        cntEps = 0;
        cntT   = 0;
        cntNT  = 0;
        if(HTrans->Epsfrei==0)
        {
            while(Suc)
            {
                if(Suc->term==2)  cntEps++;
                if(Suc->term==1)  cntT++;
                if(Suc->term==0)  cntNT++;
                Suc = Suc->suc;
            }
            cntSum = cntEps + cntT + cntNT;
            if(cntT)           HTrans->Epsfrei = 2; /* Nein */ 
            if(cntSum==cntEps) HTrans->Epsfrei = 1; /* Ja */
            if(cntNT)          Unent = 1;
        }
        HTrans = HTrans->next;
    }

    while(Unent)
    {
        Unent = 0;
        HTrans = Gram;
    
        while(HTrans)
        {
            if(HTrans->Epsfrei==0)
            {
                Suc = HTrans->suc;

                cntFrei2   = 0; 
                cntNFrei2  = 0; 
                cntUnent2  = 0;

                while(Suc)
                {
                    help = Gram;
                    cntFrei1   = 0; 
                    cntNFrei1  = 0; 
                    cntUnent1  = 0; 
          
                    while(help)
                    {
                        help = getTransBegin(help,Suc->sym);

                        if(help!=NULL)
                        {
                               if(help->Epsfrei==0) cntUnent1++;
                            if(help->Epsfrei==1) cntNFrei1++;
                            if(help->Epsfrei==2) cntFrei1++;
                            help = help->next;
                        }
                    }
        
                    cntSum = cntUnent1 + cntFrei1 + cntNFrei1;
                    if(cntUnent1)         cntUnent2++;
                    if(cntSum==cntNFrei1) cntNFrei2++;
                    if(cntFrei1)          cntFrei2++;
                    Suc = Suc->suc;
                }

                cntSum = cntUnent2 + cntFrei2 + cntNFrei2;
                if(cntUnent2)         Unent = 1;
                if(cntSum==cntNFrei2) HTrans->Epsfrei = 1;
                if(cntFrei2)          HTrans->Epsfrei = 2;
          
            }
            HTrans = HTrans->next;
        }
    }

}

/* erzeugt First-Menge */
void FirstSet(pnode Gram)
{
    pnode HTrans = Gram;
    pnode Suc;
    pnode help;
    pnode help2;
    pnode HFst;
    int Unent = 1;
    int Epsfrei;
    int SchoHier;

    while(Unent)
    {
        HTrans = Gram;
        Unent = 0;
        while(HTrans)
        {
            Suc = HTrans->suc;
            Epsfrei = 1;    
      
            while((Epsfrei)&&(HTrans->Epsfrei==2)&&(Suc))
            {
                Epsfrei = 0;
                  help = Gram;

                if(Suc->term==0)
                {
                    while(help)
                    {
                         help = getTransBegin(help,Suc->sym);

                        if(help!=NULL)
                        {
                            if(help->Epsfrei==1) Epsfrei = 1;
                            help2 = help->First;

                            while(help2)
                            {
                                 HFst = HTrans;
                                 SchoHier = 1;
                                while((HFst->First)&&(SchoHier==1)) 
                                {
                                     HFst = HFst->First;
                                     if(help2->sym==HFst->sym) SchoHier = 0;
                                }

                                if(SchoHier==1)
                                {
                                    HFst->First = NewNode();
                                    HFst = HFst->First;
                                    HFst->sym = help2->sym;
                                    Unent = 1;
                                }
                                help2 = help2->First;
                            }
                              help = help->next;
                        }
                    }
                }
                else
                {
                    HFst = HTrans;
                    SchoHier = 1;
                    while((HFst->First)&&(SchoHier==1)) 
                    {
                        HFst = HFst->First;
                        if(Suc->sym==HFst->sym) SchoHier = 0;
                    }

                    if(SchoHier==1)
                    {
                        HFst->First = NewNode();
                        HFst = HFst->First;
                        HFst->sym = Suc->sym;
                        Unent = 1;
                    }
                }
                Suc = Suc->suc;
            }
            HTrans = HTrans->next;
        }
    }
}

/* erzeugt Follow-Menge */
void FollowSet(pnode Gram)
{
    pnode HTrans = Gram;
    pnode HTrans2;
    pnode HFlw;
    pnode HFst;
    pnode Suc;
    pnode help;
    int SchoHier;
    int Unent = 1;
    int Epsfrei;

    while(Unent)
    {
        Unent = 0;
        while(HTrans) /* HTrans entspricht dem A */ 
        {
            HTrans2 = Gram;
            while(HTrans2) /* sucht nach dem Zeichen von HTrans in den Produktionen */
            {
                help = HTrans2->suc; /* HTrans2 entspricht dem B */
                while(help)
                {
                    help = getTransInside(help,HTrans->sym);
                    if(help!=NULL)
                    {
                        help = help->suc; /* help entspricht dem Beta */
                        Epsfrei = 1;
                        while(Epsfrei)
                        {
                            Epsfrei = 0;
                            if(help==NULL)
                            {
                                Suc = HTrans2->Follow;

                                while(Suc)
                                {
                                    HFlw = HTrans;
                                    SchoHier = 1;

                                    while((HFlw->Follow)&&(SchoHier==1)) 
                                    {
                                        HFlw = HFlw->Follow;
                                        if(Suc->sym==HFlw->sym) SchoHier = 0;
                                    }
        
                                    if(SchoHier==1)
                                    {
                                        HFlw->Follow = NewNode();
                                        HFlw = HFlw->Follow;
                                        HFlw->sym = Suc->sym;
                                        Unent = 1;
                                    }

                                    Suc = Suc->Follow;
                                }
                            }
                            else
                            {
                                if(help->term==1)
                                {
                                    HFlw = HTrans;
                                    SchoHier = 1;
                                    while((HFlw->Follow)&&(SchoHier==1)) 
                                    {
                                        HFlw = HFlw->Follow;
                                        if(help->sym==HFlw->sym) SchoHier = 0;
                                    }

                                    if(SchoHier==1)
                                    {
                                        HFlw->Follow = NewNode();
                                        HFlw = HFlw->Follow;
                                        HFlw->sym = help->sym;
                                        Unent = 1;
                                    }
                                }
                                if(help->term==0)
                                {
                                    Suc = Gram;
        
                                    while(Suc)
                                    {
                                        Suc = getTransBegin(Suc,help->sym);
                                        if(Suc!=NULL)
                                        {
                                            HFst = Suc->First;
                                            while(HFst)
                                            {
                                                HFlw = HTrans;
                                                SchoHier = 1;
                        
                                                while((HFlw->Follow)&&(SchoHier==1)) 
                                                {
                                                    HFlw = HFlw->Follow;
                                                    if(HFst->sym==HFlw->sym) SchoHier = 0;
                                                }

                                                if(SchoHier==1)
                                                {
                                                    HFlw->Follow = NewNode();
                                                    HFlw = HFlw->Follow;
                                                    HFlw->sym = HFst->sym;
                                                    Unent = 1;
                                                }
                                                HFst = HFst->First;
                                            }
                                            if(Suc->Epsfrei==1)    Epsfrei = 1;
                                            Suc = Suc->next;
                                        }
                                    }
                                }
                            }
                            if(Epsfrei==1) help = help->suc;
                        }
                    }
                }
                HTrans2 = HTrans2->next;
            }
            HTrans = HTrans->next;
        }
    }
}

void ShowTables(pnode Gram)
{
    pnode HTrans = Gram;
    pnode Suc;
    pnode HFst;
    pnode HFlw;
    int count = 0;

    printf("Num\tTrans\tEps\tFirst\tFollow\n");
    while(HTrans)
    {
        printf("%d\t%c->",count,HTrans->sym);
        Suc  = HTrans->suc;
        HFst = HTrans->First;
        HFlw = HTrans->Follow;
        while(Suc)
        {
            printf("%c",Suc->sym);
            Suc = Suc->suc;
        }

        if(HTrans->Epsfrei==1)    printf("\tj");
        else                    printf("\tn");

        printf("\t{");
        while(HFst)
        {
            printf("%c",HFst->sym);
            HFst = HFst->First;
            if(HFst!=NULL) printf(",");
        }
        printf("}\t{");
        while(HFlw)
        {
            printf("%c",HFlw->sym);
            HFlw = HFlw->Follow;
            if(HFlw!=NULL) printf(",");
        }
        printf("}\n");
        count++;
        HTrans = HTrans->next;
    }
    printf("\n");
}

void ShowStack(pnode FrstEl)
{
    pnode help = FrstEl;
    while(help)
    {
        printf("%c",help->sym);
        help = help->next;
    }
    printf("\n");
}

void ParseLL1(pnode Gram,char* Text)
{
    pnode FrstEl  = NULL;
    pnode help   = NULL;
    pnode FSym;
    pnode HTrans;
    pnode Ersetz;
    pnode Next;
    int   count = 0;
    char  Sym;

    FrstEl = NewNode();
    Sym = Text[count];
    FrstEl->sym  = Gram->sym;
    FrstEl->term = Gram->term;

    while((Sym!=0)&&(FrstEl!=NULL))
    {

        printf("%c\t",Sym);
        ShowStack(FrstEl);

        if(FrstEl->term==1)
        {
            FSym = FrstEl->next;
            free(FrstEl);
            FrstEl = FSym;
            count++;
            Sym = Text[count];
        }
        else
        {
            HTrans = Gram;
            Ersetz = NULL;
            while(HTrans) /* sucht nach der zu ersetzenden Regel */
            {
                HTrans = getTransBegin(HTrans,FrstEl->sym); /* Geht dei Regeln durch */
                if(HTrans!=NULL)
                {
                    /* FSym enthält die zu vergleichenden Zeichen */
                    if(HTrans->Epsfrei==1)    FSym = HTrans->Follow;
                    else                    FSym = HTrans->First;

                    while(FSym!=NULL) /* sucht nach dem Zeichen */
                    {
                        if(FSym->sym==Sym)        Ersetz = HTrans;
                        if(HTrans->Epsfrei==1)    FSym = FSym->Follow;
                        else                    FSym = FSym->First;
                    }
                    HTrans = HTrans->next;
                }
            }
    
            Ersetz = Ersetz->suc;
            FSym = FrstEl->next;
            free(FrstEl);
            FrstEl = NULL;

            if(Ersetz->term==2)
            {
                FrstEl = FSym;
            }
            else
            {
                while(Ersetz!=NULL)
                {
                    help = NewNode();
                    help->sym  = Ersetz->sym;
                    help->term = Ersetz->term;
                    Ersetz = Ersetz->suc;

                    if(FrstEl==NULL)    FrstEl = help;
                    else                Next->next = help;
                    Next = help;
                }
                Next->next = FSym;
            }
        }
    }
}

void DeleteTables(pnode Gram)
{
    pnode HTrans = Gram;
    pnode Suc;
    pnode HFst;
    pnode HFlw;
    pnode help;

    while(HTrans)
    {
        Suc  = HTrans->suc;
        HFst = HTrans->First;
        HFlw = HTrans->Follow;
        while(Suc)
        {
            help = Suc;
            Suc = Suc->suc;
            free(help);
        }
        while(HFst)
        {
            help = HFst;
            HFst = HFst->First;
            free(help);
        }
        while(HFlw)
        {
            help = HFlw;
            HFlw = HFlw->Follow;
            free(help);
        }
        help = HTrans;
        HTrans = HTrans->next;
        free(help);
    }
}

pnode LL0Table(pnode Gram)
{
    return NULL;
}

int LL1Analyse(char* BNF,char* Text)
{
    pnode Gram = Transform(BNF);
    EpsilonTable(Gram);
    FirstSet(Gram);
    FollowSet(Gram);
    ShowTables(Gram);
    ParseLL1(Gram,Text);
    DeleteTables(Gram);
    return 0;
}

int SLR1Analyse(char* BNF,char* Text)
{
    pnode Gram = Transform(BNF);
    EpsilonTable(Gram);
    FirstSet(Gram);
    FollowSet(Gram);
    ShowTables(Gram);
    LL0Table(Gram);
    DeleteTables(Gram);
    return 0;
}

int main(int argc,char **argv)
{
    char BspBNF[] = "S=E#.E=TU.U=+TU.U=&.T=FV.V=*FV.V=&.F=z.F=(E).";
    char BspText[] = "z+(z+z)*z#";
    if(argc!=3)
    {
        printf("Aufruf: %s '%s' '%s'\n",argv[0],BspBNF,BspText);
        LL1Analyse(BspBNF,BspText);
    }
    else
    {
        LL1Analyse(argv[1],argv[2]);
    }
    return 0;
}
Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.