编译原理LALR分析表构造

2019-06-24  本文已影响0人  吃茶的武士

代码可以直接运行。如果不能就去notepad中调整一下字符编码。

【实验名称】              LALR预测分析表的构造                 

【实验目的】

 根据书本P148页,LALR预测分析内容,理解LALR(1)和前面LR文法的区别与联系。

【实验原理】

在LALR(1)文法中,引入了一个新的概念,同心集。

同心集是指前面产生式相同,只是后面的超前搜索字符不一样。同心集合并后产生式不变,超前搜索字符变为合并前几个产生式的合集。

LALR(1)与LR(1)的不同之处就是有合并同心集这一操作。其余的实现步骤就要查看LR(1)文法的实现。LR(1)文法与LR(0)文法的不同又是携带了超前搜索字符。超前搜索字符的算法,在书本P145有如下定义

[if !supportLists]1. [endif]假定I是一个项目集合,I的任何项目集合都属于CLOSURE(I)

[if !supportLists]2. [endif]如果有项目A->a.Bp.a属于CLOSURE(I),B->y是文法产生式,p属于终结符集合,b属于First(pa),那么B->.y,b也属于CLOSURE(I)

[if !supportLists]3. [endif]重复第二步,直到CLOSURE(I)不再增大。

【实验内容】

由上面的原理分析可得。从之前的实验‘LR(0)’分析表入手,给每一个产生式带上超前搜索字符。注意,在第一个产生式“S’->S”的超前搜索字符初始化为#。再根据上面的步骤来求出每个产生式的搜索字符。最后合并同心集,把超前搜索字符做合集。那么新的预测分析表和以前的LR(0)不同之处在于,一个终结符对应的下一个状态可能有多个。比如(S5,S7),那么就需要选一个代表一下就OK。

【小结或讨论】

      这两次实验都是针对第六章LR家族来做的,一个是最简单的LR(0),一个是最后限制性较强的LALR(1)。一共四个LR家族的分析方法,LR(0)不可以出现“规约-规约”与“规约-移进”冲突,一旦出现就要考虑是否可以用SLR(1)的方法来解决冲突,限定为SLR(1)方法。LR(1)方法加入了超前搜索字符,对于一样的规约式,超前搜索字符不一样,那么就是不同的状态,比前两者更为精确。LALR(1)在LR(1)的基础上,为了简化闭包运算,就引入同心集合并。

      这一部分内容很多,题目也很多。运算量感觉很大,有时候理解了,却又记不住方法,需要多加练习,还涉及到离散数学的相关知识。收获很多。

【实验截图】

文件中存放的文法

实验结果:(这个例子举得不好,没有体现合并同心集)

第二个文法:

实验结果:

代码:

#include

<cstdio>

#include

<cstring>

#include

<map>

#include

<vector>

#include

<queue>

#include

<algorithm>

#include

<iostream>

#include

<string>

#include

<stdio.h>

using namespace std;

#define INF 0x3f3f3f3f

struct grammar{

    char vn, s[10];

}g[100];

int g_num;

map<char, int> vn_map;

map<char, int> vt_map;

int vn_num, vt_num;

char vn[20], vt[20];

int first[20][20];

struct project{

    grammar g;

    int k, pre[20];

};

vector<project> closure[100];

int closure_num;

struct Edge{

    int u, v;

    int next;

    char ch;

}edge[1000];

int go[100];

int edge_num;

int belong[100];

int merge_num;

int lalr1_action[100][20], lalr1_goto[100][20];

void read() {

    g_num= 0;

    int i, j, len, flag;

    char ch, str[20];

    grammar temp;

    while( gets(str) ) {

        if( str[0] == '@' )

            break;

        len= strlen(str);

        flag= 0;

        if( len < 4 ) flag = 1;

        else if( str[0] < 'A' || str[0] > 'Z' || str[1] != '-' || str[2] != '>' )

            flag= 1;

        else

        {

            temp.vn = str[0];

            for(i = 3; i < len; i++) {

                if( str[i] == ' ' ) break;

                temp.s[i-3] = str[i];

            }

            temp.s[i-3] = '\0';

            if( i < len )

               flag= 1;

        }

        if( flag ) {

            printf("产生式%s不符合文法规则,已忽略。\n", str);

            continue ;

        }

        else {

            g[ ++g_num ] = temp;

        }

    }

    if( g_num == 0 ) {

        printf("未成功输入产生式\n");

        return;

    }

    printf("共输入%d条产生式\n", g_num);

    g[0].vn = '$';

    g[0].s[0] = g[1].vn;

    g[0].s[1] = '\0';

    printf("\n拓广文法:%c->%s\n", g[0].vn, g[0].s);

    for(i = 1; i <= g_num; i++) {

        printf("\t %c->%s\n", g[i].vn, g[i].s);

    }

    vn_num= vt_num = 0;

    if( vt_map['@'] == 0 ) {

        vt_map['@'] = ++vt_num;

        vt[vt_num] = '@';

    }

    for(i = 0; i <= g_num; i++) {

        ch= g[i].vn;

        if( vn_map[ch] == 0 ) {

            vn_map[ch] = ++vn_num;

            vn[vn_num] = ch;

        }

        len= strlen( g[i].s );

        for(j = 0; j < len; j++) {

            ch= g[i].s[j];

            if( ch >= 'A' && ch <= 'Z' ) continue;

            if( vt_map[ch] == 0 ) {

                vt_map[ch] = ++vt_num;

                vt[vt_num] = ch;

            }

        }

    }

    if( vt_map['#'] == 0 ) {

        vt_map['#'] = ++vt_num;

        vt[vt_num] = '#';

    }

    return;

}

void dfs(char ch,int acc[],int vis[],int val[]) {

    int i, j, k, c = vn_map[ch];

    if( acc[c] ) {

        for(i = 1; i <= vt_num; i++)

            val[i] = first[c][i];

        return;

    }

    int value[20];

    memset(value,0,sizeof(value));

    for(i = 0; i <= g_num; i++) {

        if( vis[i] ) continue;

        vis[i] = 1;

        if( g[i].vn != ch ) continue;

        int len = strlen( g[i].s );

        for(j = 0; j < len; j++) {

            char sh = g[i].s[j];

            if( vn_map[sh] ) {

                dfs(sh,acc,vis,value);

                for(k = 2; k <= vt_num; k++) {

                    if( value[k] ) val[k] = 1;

                }

                if( value[1] == 0 ) break;

            }

            else {

                c= vt_map[sh];

                val[c] = 1;

                break;

            }

        }

        if( j == len ) val[1] = 1;

    }

    return;

}

void solve_first() {

    int acc[20], vis[20], value[20];

    int i, j, k;

    memset(first,0,sizeof(first));

    memset(acc,0,sizeof(acc));

    for(i = 1; i <= vn_num; i++) {

        if( acc[i] ) continue;

        memset(vis,0,sizeof(vis));

        memset(value,0,sizeof(value));

        dfs(vn[i],acc,vis,value);

        for(j = 1; j <= vt_num; j++)

            first[i][j] = value[j];

        acc[i] = 1;

    }

    return;

}

int Equal(grammar u,grammar v) {

    if( u.vn != v.vn ) return 0;

    if( !strcmp(u.s,v.s) ) return 1;

    return 0;

}

int Equal(project u,project v) {

    if( !Equal(u.g,v.g) ) return 0;

    if( u.k != v.k ) return 0;

    for(int i = 1; i <= vt_num; i++)

        if( u.pre[i] != v.pre[i] ) return 0;

    return 1;

}

int Equal(int x,int y) {

    int i, j;

    if( closure[x].size() != closure[y].size() ) return 0;

    for(i = 0; i < closure[x].size(); i++) {

        project u= closure[x][i];

        for(j = 0; j < closure[y].size(); j++) {

            project v= closure[y][j];

            if( Equal(u,v) ) break;

        }

        if( j == closure[y].size() ) break;

    }

    if( i == closure[x].size() ) return 1;

    return 0;

}

project newproject() {

    project temp;

    memset(temp.pre,0,sizeof(temp.pre));

    return temp;

}

int addproject(project temp,int c) {

    for(int i = 0; i < closure[c].size(); i++) {

        project old= closure[c][i];

        if( Equal(old.g,temp.g) && old.k == temp.k ) return i;

    }

    return -1;

}

int solve_closure(int c){

    int i, j, k, l;

    for(i = 0; i < closure[c].size(); i++) {

        project old= closure[c][i];

        int len = strlen( old.g.s );

        if( old.k == len ) continue;

        char vn = old.g.s[ old.k ];

        if( vt_map[vn] ) break;

        for(j = 0; j <= g_num; j++) {

            if( g[j].vn != vn ) continue;

            project temp= newproject();

            temp.g = g[j];

            temp.k = 0;

            for(k = 0; k < strlen( g[j].s ); k++) {

                if( g[j].s[k] == '@' ) temp.k++;

                else break;

            }

            char ch = old.g.s[old.k+1];

            if( ch == '\0' ) {

                for(k = 1; k <= vt_num; k++)

                    temp.pre[k] = old.pre[k];

            }

            else if( vn_map[ch] ) {

                for(k = 1; k <= vt_num; k++)

                    temp.pre[k] = first[ vn_map[ch] ][k];

            }

            else

                temp.pre[ vt_map[ch] ] = 1;

            int flag = addproject(temp,c);

            if( flag == -1 ) closure[c].push_back(temp);

            else {

                for(k = 1; k <= vt_num; k++)

                    if( temp.pre[k] ) closure[c][flag].pre[k] = 1;

            }

        }

    }

    for(i = 1; i < c; i++) {

        if( Equal(i,c) ) return i;

    }

    return c;

}

void addedge(int u,int v,char ch) {

    edge[edge_num].u = u;

    edge[edge_num].v = v;

    edge[edge_num].ch = ch;

    edge[edge_num].next = go[u];

    go[u] = edge_num++;

}

void solve_projects() {

    project temp= newproject();

    closure_num= 0;

    temp.g = g[0];

    temp.k = 0;

    temp.pre[ vt_map['#'] ] = 1;

    closure[closure_num+1].clear();

    closure[closure_num+1].push_back(temp);

    int c = solve_closure(closure_num+1);

    if( c == closure_num+1 ) {

        closure_num++;

    }

    int i, j, k;

    memset(go,-1,sizeof(go));

    edge_num= 0;

    for(i = 1; i <= closure_num; i++) {

        printf("项目集%d包含:\n", i);

        for(j = 0; j < closure[i].size(); j++) {

            project old= closure[i][j];

            printf("\t%c->", old.g.vn);

            for(k = 0; k <= strlen( old.g.s ); k++) {

                if( k == old.k ) printf(".");

                printf("%c", old.g.s[k]);

            }

           // printf("\t");

            for(k = 1; k <= vt_num; k++)

                if( old.pre[k] ) {

                printf(","); printf("%c ", vt[k]);}

            printf("\n");

        }

        int vis[100];

        memset(vis,0,sizeof(vis));

        for(j = 0; j < closure[i].size(); j++) {

            if( vis[j] ) continue;

            project old= closure[i][j];

            int len = strlen(old.g.s);

            if( old.k == len ) continue;

            closure[ closure_num+1 ].clear();

            for(k = j; k < closure[i].size(); k++) {

                project oldd= closure[i][k];

                if( oldd.g.s[ oldd.k ] == old.g.s[ old.k ] ) {

                    vis[k] = 1;

                    project temp= oldd;

                    temp.k++;

                    closure[ closure_num+1 ].push_back(temp);

                }

            }

            if( closure[ closure_num+1 ].size() == 0 ) continue;

            c= solve_closure(closure_num+1);

            if( c == closure_num+1 ) {

                closure_num++;

            }

            addedge(i,c,old.g.s[ old.k ]);

        }

    }

    return;

}

int findgrammar(grammar temp) {

    for(int i = 0; i <= g_num; i++) {

        if( Equal(temp,g[i]) ) return i;

    }

}

int Equalproject(int x,int y) {

    if( closure[x].size() != closure[y].size() ) return 0;

    int i, j, k;

    for(i = 0; i < closure[x].size(); i++) {

        project u= closure[x][i];

        for(j = 0; j < closure[y].size(); j++) {

            project v= closure[y][j];

            if( u.k == v.k &&Equal(u.g,v.g) ) break;

        }

        if( j == closure[y].size() ) return 0;

    }

    return 1;

}

void project_merge() {

    int i, j, k;

    merge_num= 0;

    int vis[100];

    memset(vis,0,sizeof(vis));

    for(i = 1; i <= closure_num; i++) {

        if( vis[i] ) continue;

        belong[i] = ++merge_num;

        vis[i] = 1;

        for(j = i+1; j <= closure_num; j++) {

            if( Equalproject(i,j) ) {

                belong[j] = merge_num;

                vis[j] = 1;

            }

        }

    }

    printf("\n项目集合并:\n");

    for(i = 1; i <= merge_num; i++) {

        printf("新项目集%d包含项目集:", i);

        for(j = 1; j <= closure_num; j++)

            if( belong[j] == i ) printf("%d ", j);

        printf("\n");

    }

}

void solve_lalr1() {

    int flag = 0;

    memset(lalr1_action,INF,sizeof(lalr1_action));

    memset(lalr1_goto,INF,sizeof(lalr1_goto));

    int i, j, k;

    for(i = 1; i <= closure_num; i++) {

        for(j = 0; j < closure[i].size(); j++) {

            project old= closure[i][j];

            char ch = old.g.s[ old.k ];

            int c = findgrammar(old.g);

            if( ch == '\0' ) {

                for(k = 1; k <= vt_num; k++) {

                    if( old.pre[k] ) {

                        if( lalr1_action[ belong[i] ][k] == INF || lalr1_action[ belong[i] ][k] == c )

                            lalr1_action[ belong[i] ][k] = c;

                        else flag = 1;

                    }

                }

            }

        }

        for(j = go[i]; j != -1; j = edge[j].next) {

            int u = belong[edge[j].u], v = belong[edge[j].v];

            char ch = edge[j].ch;

            if( vn_map[ch] ) {

                if( lalr1_goto[u][ vn_map[ch] ] == INF || lalr1_goto[u][ vn_map[ch] ] == -v )

                    lalr1_goto[u][ vn_map[ch] ] = -v;

                else flag = 1;

            }

            else {

                if( lalr1_action[u][ vt_map[ch] ] == INF || lalr1_action[u][ vt_map[ch] ] == -v )

                    lalr1_action[u][ vt_map[ch] ] = -v;

                else flag = 1;

            }

        }

    }

    if( flag ) {

        printf("出现冲突,该文法不是LALR(1)文法\n");

        return;

    }

    printf("\nLALR(1)分析表:\n");

    printf("状态\t");

    for(i = 1; i <= vt_num; i++)

        printf("%c\t", vt[i]);

    for(i = 1; i <= vn_num; i++)

        printf("%c\t", vn[i]);

    printf("\n");

    for(i = 1; i <= merge_num; i++) {

        printf("%d\t", i);

        for(j = 1; j <= vt_num; j++) {

            k= lalr1_action[i][j];

            if( k == INF ) printf("\t");

            else if( k < 0 ) printf("S%d\t", -k);

            else printf("r%d\t", k);

        }

        for(j = 1; j <= vn_num; j++) {

            k= lalr1_goto[i][j];

            if( k == INF ) printf("\t");

            else if( k < 0 ) printf("%d\t", -k);

            else printf("r%d\t", k);

        }

        printf("\n");

    }

    return ;

}

int main() {

    freopen("LALR(1).txt","r",stdin);

    read();

    solve_first();

    solve_projects();

    project_merge();

    solve_lalr1();

    return 0;

}

上一篇下一篇

猜你喜欢

热点阅读