算符优先算法 编译原理

#include <bits/stdc++.h>
#define FOR(i,s,t) for(int i=(s);i<=(t);i++)
#define ROF(i,s,t) for(int i=(s);i>=(t);i--)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define fi first
#define se second
#define endl '\n'
const int MAX = 500 + 1;
using namespace std;

struct TSET{
    public:
    string left;
    vector<string> right;
    TSET ( const string& str ){left = str;}
    void insert ( char str[] ){right.pb(str);}
    void print ( ){
        printf ( "%s->%s" , left.c_str() , right[0].c_str() );
        for ( int i = 1 ; i < right.size() ; i++ )
            printf ( "|%s" , right[i].c_str() );
        puts("");
    }
};

char rlt[MAX][MAX];
vector<char> VT;
vector<TSET> VNset;
map<string,int> VNdic;
set<char> FIRSTVT[MAX], LASTVT[MAX];
int used[MAX], vis[MAX];

bool IsVN(char c){
    return isupper(c);
}
void dfs (  int x ) { //深度优先搜索
    if ( vis[x] ) return;
    vis[x] = 1;
    auto left = VNset[x].left;
    FOR(i,0,(int)VNset[x].right.size()-1){
        auto str = VNset[x].right[i];
        if ( IsVN(str[0]) ) {
            int y = VNdic[str.substr(0,1)]-1;
            if ( str.length() > 1 && !IsVN(str[1] ) )
                FIRSTVT[x].insert ( str[1] );
            dfs ( y );
            for (auto _ : FIRSTVT[y])FIRSTVT[x].insert(_);
        }
        else FIRSTVT[x].insert ( str[0] );
    }
}

void make_FIRSTVT ( ){
    memset ( vis , 0 , sizeof ( vis ) );
    //for ( int i = 0 ; i < VNset.size() ; i++ )
    FOR(i,0,(int)VNset.size()-1)
        if ( vis[i] ) continue;
        else dfs ( i );
#define DEBUG
#ifdef DEBUG
    puts("------------FIRSTVTVT集-------------------");
    for ( int i = 0 ; i < VNset.size() ; i++ )
    {
        printf ( "%s : " , VNset[i].left.c_str() );
        set<char>::iterator it = FIRSTVT[i].begin();
        for ( ; it!= FIRSTVT[i].end() ; it++ )
            printf ( "%c " , *it );
        puts ("" );
    }
#endif
}

void dfs1 ( int x ){ //深度优先搜索
    if ( vis[x] ) return;
    vis[x] = 1;
    auto left = VNset[x].left;
    FOR(i, 0, (int)VNset[x].right.size()-1){
        auto str = VNset[x].right[i];
        int n = str.length() -1;
        if ( IsVN(str[n] ) ){
            int y = VNdic[str.substr(n,1)]-1;
            if ( str.length() > 1 && !IsVN(str[n-1]) )
                LASTVT[x].insert ( str[1] );
            dfs1 ( y );
            for (auto _:LASTVT[y]) LASTVT[x].insert(_);
        }
        else
            LASTVT[x].insert ( str[n] );
    }
}

void make_LASTVT ( ){
    memset ( vis , 0 , sizeof ( vis ) );
    for ( int i = 0 ; i < VNset.size() ; i++ )
        if ( vis[i] ) continue;
        else dfs1 ( i );
#define DEBUG
#ifdef DEBUG
    puts("--------------LASTVTVT集---------------------");
    for ( int i = 0 ; i < VNset.size() ; i++ )
    {
        printf ( "%s : " , VNset[i].left.c_str() );
        set<char>::iterator it = LASTVT[i].begin();
        for ( ; it!= LASTVT[i].end() ; it++ )
            printf ( "%c " , *it );
        puts ("" );
    }
#endif
}

void make_table ( ){ //构造分析表
    FOR(i,0,MAX-1)FOR(j,0,MAX-1) rlt[i][j] = ' ';
    FOR(i, 0,(int)VNset.size()-1)
        FOR(j, 0,(int)VNset[i].right.size()-1){
            auto str = VNset[i].right[j];
            FOR(k, 0, (int)str.length()-1){
                if ( !IsVN(str[k]) && !IsVN(str[k+1]) )
                    rlt[str[k]][str[k+1]] = '=';
                if ( !IsVN(str[k]) && IsVN(str[k+1]) ){
                    int x = VNdic[str.substr(k+1,1)]-1;
                    for (auto _:FIRSTVT[x]) rlt[str[k]][_] = '<';
                }
                if ( IsVN(str[k]) && !IsVN(str[k+1]) ){
                    int x = VNdic[str.substr(k,1)]-1;
                    for (auto _:LASTVT[x])  rlt[_][str[k+1]] = '>';
                }
                if ( k > str.length()-2 ) continue;
                if ( !IsVN(str[k]) && !IsVN(str[k+2]) && IsVN(str[k+1]) )
                    rlt[str[k]][str[k+2]] = '=';
            }
        }
#define DEBUG
#ifdef DEBUG
    for ( int i = 0 ; i < VT.size()*5 ; i++ )
        printf ("-");
    printf ( "算符优先关系表" );
    for ( int i = 0 ; i < VT.size()*5 ; i++ )
        printf ( "-" );
    puts("");
    printf ( "|%8s|" , "" );
    for ( int i = 0 ; i < VT.size() ; i++ )
        printf ( "%5c%5s" , VT[i] , "|" );
    puts ("");
    for ( int i = 0 ; i < (VT.size()+1)*10 ; i++ )
        printf ("-");
    puts("");
    for ( int i = 0 ; i < VT.size() ; i++ )
    {
        printf ( "|%4c%5s" , VT[i] , "|");
        for ( int j = 0 ; j < VT.size() ; j++ )
            printf ( "%5c%5s" , rlt[VT[i]][VT[j]] , "|" );
        puts ("");
        for ( int i = 0 ; i < (VT.size()+1)*10 ; i++ )
            printf ("-");
        puts("");
    }
#endif
}

int fa[MAX];
/************************并查集**********************/
int _find ( int x  ) { //并查集查询,路径压缩
    return x==fa[x]?x:fa[x] = _find ( fa[x] );
}

bool judge ( char x , char y ){ //判断两个是否再同一个集合
    if ( _find ( x ) == _find ( y ) ) return true;
    return false;
}

void _union ( char x , char y ){ //合并两个集合
    x = _find(x); y = _find(y);
    fa[x] = y;
}

void print ( string s1 , string s2 , string s3 , string s4 , string s5 , string s6 ){
    printf ( "%s\t|%-15s%-15s%-15s%-15s%-15s\n" , s1.c_str(), s2.c_str(), s3.c_str() ,s4.c_str(),s5.c_str() , s6.c_str() );
}

void init ( )
{
    FOR(i,0,MAX-1) fa[i] = i; //并查集的初始化,首先将每一个元素独立分在一个集合中
    FOR(i, 0, (int)VNset.size() -1) {
        auto left = VNset[i].left;
        FOR(j, 0, (int)VNset[i].right.size() - 1){
            auto str = VNset[i].right[j];
            if ( left.length() == 1 && str.length() == 1 ) _union ( left[0] , str[0] );
        }
    }
    print("步骤","栈","优先关系","当前符号","剩余符号","动作");
}

string get_stk ( vector<char>& stk ){
    string ret = "";
    for ( int i = 0 ; i < stk.size() ; i++ ) ret += stk[i];
    return ret;
}

bool check ( const string& str1 , const string& str2 ){
    if ( str1.length() != str2.length() ) return false;
    FOR(i, 0,(int)str1.length()-1)
        if ( IsVN(str1[i]) ){
            if ( !judge(str1[i],str2[i])) return false;
        }
        else{
            if ( str1[i] != str2[i] ) return false;
        }
    return true;
}

string reduction ( string src ){
    FOR(i, 0, (int)VNset.size()-1) FOR(j, 0, (int)VNset[i].right.size()-1)
            if ( check ( VNset[i].right[j] , src ) ){
                return VNset[i].left;
            }
    return "";
}

void move_reduction ( string src ){
    init ();
    vector<char> stk;
    int steps= 1;
    src += "#";
    stk.pb ( '#' );
    FOR (i, 0, (int)src.length()-1){
        char top = stk[stk.size()-1];
        ROF(j, (int)stk.size()-1, 0)
            if ( IsVN(stk[j]) ) continue;
            else{
                top = stk[j];
                break;
            }
        char ch = rlt[top][src[i]];
        string temp ="";
        if ( ch == '<' || ch == '=' ){ //如果在分析表中是‘<’ 或者是‘=’,则‘移进’
            if ( i == src.length() - 1 ){
                printf("%d", steps);
                print (temp, get_stk( stk ) , temp+ch , temp+src[i] , "" , "移进" );
            }
            else{
                printf("%d", steps);
                print ( temp , get_stk( stk ) , temp+ch , temp+src[i] , src.substr(i+1,src.length()-i-1) , "移进" );
            }
            stk.pb ( src[i] );
        }
        else{ //如果出现‘>’ 则‘规约’
            string temp ="";
            string str ="";
            int x = stk.size()-2;
            if ( i == src.length() ){
                printf("%d", steps);
                print ( temp , get_stk(stk) , temp+ch , temp + src[i] , "" , "归约" );
            }
            else{
                printf("%d", steps);
                print ( temp , get_stk(stk) , temp+ch , temp + src[i] , src.substr(i+1,src.length()-i-1) , "归约" );
            }
            while (1) {
                if ( x == 0 ) break;
                if ( !IsVN(stk[x] ) && rlt[stk[x]][top] == '<' )
                        break;
                x--;
            }
            ROF(j, (int)stk.size()-1, x + 1) {
                str += stk[j];
                stk.pop_back();
            }
            //cout << str << endl;
            reverse(str.begin(), str.end());
            str = reduction(str);
            //str = "N";
            FOR(j, 0, (int)str.length() - 1)
                stk.pb ( str[j] );
            i--;
        }
        steps++;
    }
}

int main ( ){
    int n;
    char s[MAX];
    printf("请输入文法:\n");
    scanf ( "%d" , &n );
    memset ( used , 0 , sizeof ( used ) );
    FOR(i, 0, n - 1) {
        scanf ( "%s" , s );
        int len = strlen(s), j = 0;
        for (; j < len ; j++ )
            if ( s[j] == '-' )
                break;
        s[j] = 0;
        if ( !VNdic[s] ){
            VNset.pb ( TSET(s) );
            VNdic[s] = VNset.size();
        }
        int x = VNdic[s]-1;
        VNset[x].insert ( s+j+2 );
        FOR(k , 0, j - 1)
            if ( !IsVN(s[k] ) ){
                if ( used[s[k]] ) continue;
                used[s[k]] = 1;
                VT.pb ( s[k] );
            }
        FOR(k, j + 2, len - 1)
            if ( !IsVN(s[k] ) ) {
                if ( used[s[k]] ) continue;
                VT.pb ( s[k] );
                used[s[k]] = VT.size();
            }
    }
#define DEBUG
#ifdef DEBUG
        puts ("************VT集*******************");
        for ( int i = 0 ; i < VT.size() ; i++ )
            printf ( "%c " , VT[i] );
        puts ("");
        puts("*************产生式*****************");
        for ( int i = 0 ; i < VNset.size() ; i++ )
            VNset[i].print();
        puts("************************************");
#endif
    make_FIRSTVT();
    make_LASTVT();
    make_table();
    string teststr;
    printf("请输入代分析串:\n");
    cin >> teststr;
    move_reduction(teststr);
}
/*
11
S->#E#
E->E+T
E->E-T
E->T
T->T*F
T->T/F
T->F
F->P^F
F->P
P->(E)
P->i

9
S->#E#
E->E@T
E->T
T->T&F
T->F
F->P^F
F->P
P->(E)
P->i

*/

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值